Revision 45144
Added by Claudio Atzori over 7 years ago
modules/dnet-oai-store-service/src/main/resources/eu/dnetlib/applicationContext-dnet-oai-store-service.xml | ||
---|---|---|
1 |
<?xml version="1.0" encoding="UTF-8"?> |
|
2 |
<beans xmlns="http://www.springframework.org/schema/beans" |
|
3 |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" |
|
4 |
xmlns:sec="http://cxf.apache.org/configuration/security" xmlns:wsa="http://cxf.apache.org/ws/addressing" |
|
5 |
xmlns:p="http://www.springframework.org/schema/p" xmlns:http="http://cxf.apache.org/transports/http/configuration" |
|
6 |
xmlns:t="http://dnetlib.eu/springbeans/t" xmlns:template="http://dnetlib.eu/springbeans/template" |
|
7 |
xmlns:util="http://www.springframework.org/schema/util" |
|
8 |
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd |
|
9 |
http://cxf.apache.org/ws/addressing http://cxf.apache.org/schemas/ws-addr-conf.xsd |
|
10 |
http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd |
|
11 |
http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd |
|
12 |
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd |
|
13 |
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd |
|
14 |
http://dnetlib.eu/springbeans/template http://dnetlib.eu/springbeans/template.xsd"> |
|
15 |
|
|
16 |
<!-- endpoints --> |
|
17 |
<jaxws:endpoint id="oaiStoreServiceEndpoint" |
|
18 |
implementor="#oaiStoreService" implementorClass="eu.dnetlib.data.oai.store.OAIStoreService" |
|
19 |
address="/oaistore" /> |
|
20 |
|
|
21 |
<template:instance name="serviceRegistrationManager" |
|
22 |
t:serviceRegistrationManagerClass="eu.dnetlib.enabling.tools.registration.ValidatingServiceRegistrationManagerImpl" |
|
23 |
t:name="oaiStoreServiceRegistrationManager" t:service="oaiStoreService" |
|
24 |
t:endpoint="oaiStoreServiceEndpoint" t:jobScheduler="jobScheduler" |
|
25 |
t:serviceRegistrator="blackboardServiceRegistrator" /> |
|
26 |
|
|
27 |
<bean id="oaiStoreService" class="eu.dnetlib.data.oai.store.OAIStoreServiceImpl" |
|
28 |
init-method="start" destroy-method="stop" p:notificationHandler-ref="oaiStoreNotificationHandler" /> |
|
29 |
|
|
30 |
<bean id="oaiStoreNotificationHandler" |
|
31 |
class="eu.dnetlib.enabling.tools.blackboard.BlackboardServerExecutorNotificationHandler" |
|
32 |
p:blackboardExecutor-ref="oaiStoreBlackboardExecutor" /> |
|
33 |
|
|
34 |
<bean id="oaiStoreBlackboardExecutor" |
|
35 |
class="eu.dnetlib.enabling.tools.blackboard.BlackboardServerActionExecutor" |
|
36 |
p:blackboardHandler-ref="blackboardHandler" |
|
37 |
p:actionType="eu.dnetlib.data.oai.store.actions.OAIStoreActions" |
|
38 |
p:incomplete="false"> |
|
39 |
<property name="actionMap"> |
|
40 |
<map> |
|
41 |
<entry key="SYNC"> |
|
42 |
<bean class="eu.dnetlib.data.oai.store.actions.SyncAction" /> |
|
43 |
</entry> |
|
44 |
<entry key="COUNT_SETS"> |
|
45 |
<bean class="eu.dnetlib.data.oai.store.actions.CountSetsAction"/> |
|
46 |
</entry> |
|
47 |
<entry key="REFRESH_CONFIG"> |
|
48 |
<bean class="eu.dnetlib.data.oai.store.actions.RefreshConfigAction" /> |
|
49 |
</entry> |
|
50 |
<entry key="ENSURE_INDEXES"> |
|
51 |
<bean class="eu.dnetlib.data.oai.store.actions.EnsureIndexesAction" /> |
|
52 |
</entry> |
|
53 |
<entry key="CREATE_STORE"> |
|
54 |
<bean class="eu.dnetlib.data.oai.store.actions.CreateStoreAction" /> |
|
55 |
</entry> |
|
56 |
<entry key="CREATE_OAI_INDEX"> |
|
57 |
<bean class="eu.dnetlib.data.oai.store.actions.CreateOAIIndexAction" /> |
|
58 |
</entry> |
|
59 |
<entry key="DROP_STORE"> |
|
60 |
<bean class="eu.dnetlib.data.oai.store.actions.DropStoreAction" /> |
|
61 |
</entry> |
|
62 |
</map> |
|
63 |
</property> |
|
64 |
</bean> |
|
65 |
|
|
66 |
<bean id="synchronizer" class="eu.dnetlib.data.oai.store.sync.OAIStoreSynchronizer" /> |
|
67 |
|
|
68 |
<bean id="oaiHelper" class="eu.dnetlib.data.oai.store.conf.OAIHelper"/> |
|
69 |
|
|
70 |
<bean id="oaiSetsCounter" class="eu.dnetlib.data.oai.store.conf.OAISetsCounter" /> |
|
71 |
|
|
72 |
<bean id="mongoCacheHelper" class="eu.dnetlib.data.oai.store.mongo.MongoPublisherCacheHelper"/> |
|
73 |
|
|
74 |
</beans> |
modules/dnet-oai-store-service/src/main/resources/eu/dnetlib/data/oai/store/mongo/applicationContext-mongodb-publisher-store.properties | ||
---|---|---|
1 |
services.publisher.oai.host=localhost |
|
2 |
services.publisher.oai.port=27017 |
|
3 |
#services.publisher.oai.db=oaistore |
|
4 |
|
modules/dnet-oai-store-service/src/main/resources/eu/dnetlib/data/oai/store/mongo/applicationContext-mongodb-publisher-store.xml | ||
---|---|---|
1 |
<?xml version="1.0" encoding="UTF-8"?> |
|
2 |
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|
3 |
xmlns:p="http://www.springframework.org/schema/p" xmlns="http://www.springframework.org/schema/beans" |
|
4 |
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> |
|
5 |
|
|
6 |
<bean id="mongodbPublisherStoreDao" class="eu.dnetlib.data.oai.store.mongo.MongoPublisherStoreDAO" |
|
7 |
p:metadataCollection="metadata" /> |
|
8 |
|
|
9 |
<bean id="publisherMongoClient" class="com.mongodb.MongoClient"> |
|
10 |
<constructor-arg index="0" type="com.mongodb.ServerAddress"> |
|
11 |
<bean class="com.mongodb.ServerAddress"> |
|
12 |
<constructor-arg index="0" |
|
13 |
value="${services.publisher.oai.host}" /> |
|
14 |
<constructor-arg index="1" |
|
15 |
value="${services.publisher.oai.port}" /> |
|
16 |
</bean> |
|
17 |
</constructor-arg> |
|
18 |
</bean> |
|
19 |
|
|
20 |
<bean id="recordChangeDetector" class="eu.dnetlib.data.oai.store.DummyRecordChangeDetector" /> |
|
21 |
|
|
22 |
<bean id="metadataExtractor" class="eu.dnetlib.data.oai.store.mongo.MetadataExtractor" /> |
|
23 |
|
|
24 |
<bean id="recordInfoGenerator" class="eu.dnetlib.data.oai.store.mongo.RecordInfoGenerator" /> |
|
25 |
|
|
26 |
<bean id="mongoSetCollection" class="eu.dnetlib.data.oai.store.sets.MongoSetCollection" /> |
|
27 |
|
|
28 |
<bean id="provenanceExtractor" class="eu.dnetlib.data.oai.store.mongo.ProvenanceExtractor" /> |
|
29 |
|
|
30 |
<bean id="theOAICacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" |
|
31 |
p:cache-manager-ref="oaiStoreCacheManager" /> |
|
32 |
|
|
33 |
<bean id="oaiStoreCacheManager" |
|
34 |
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" |
|
35 |
p:cacheManagerName="oaiStoreCacheManger" |
|
36 |
p:configLocation="classpath:/eu/dnetlib/data/oai/store/mongo/cache/ehcache.xml" /> |
|
37 |
|
|
38 |
</beans> |
modules/dnet-oai-store-service/src/main/resources/eu/dnetlib/data/oai/store/mongo/cache/ehcache.xml | ||
---|---|---|
1 |
<ehcache> |
|
2 |
|
|
3 |
<!-- Sets the path to the directory where cache .data files are created. |
|
4 |
If the path is a Java System Property it is replaced by its value in the |
|
5 |
running VM. The following properties are translated: user.home - User's home |
|
6 |
directory user.dir - User's current working directory java.io.tmpdir - Default |
|
7 |
temp file path --> |
|
8 |
<!--<diskStore path="java.io.tmpdir" />--> |
|
9 |
|
|
10 |
|
|
11 |
<!--Default Cache configuration. These will applied to caches programmatically |
|
12 |
created through the CacheManager. The following attributes are required for |
|
13 |
defaultCache: maxInMemory - Sets the maximum number of objects that will |
|
14 |
be created in memory eternal - Sets whether elements are eternal. If eternal, |
|
15 |
timeouts are ignored and the element is never expired. timeToIdleSeconds |
|
16 |
- Sets the time to idle for an element before it expires. i.e. The maximum |
|
17 |
amount of time between accesses before an element expires Is only used if |
|
18 |
the element is not eternal. Optional attribute. A value of 0 means that an |
|
19 |
Element can idle for infinity timeToLiveSeconds - Sets the time to live for |
|
20 |
an element before it expires. i.e. The maximum time between creation time |
|
21 |
and when an element expires. Is only used if the element is not eternal. |
|
22 |
overflowToDisk - Sets whether elements can overflow to disk when the in-memory |
|
23 |
cache has reached the maxInMemory limit. --> |
|
24 |
|
|
25 |
<!-- <defaultCache maxElementsInMemory="1000" overflowToDisk="true" --> |
|
26 |
<!-- eternal="true" diskPersistent="false" timeToIdleSeconds="0" --> |
|
27 |
<!-- timeToLiveSeconds="0" memoryStoreEvictionPolicy="LRU" --> |
|
28 |
<!-- diskExpiryThreadIntervalSeconds="120" diskSpoolBufferSizeMB="5" /> --> |
|
29 |
|
|
30 |
|
|
31 |
<cache name="oaistores" maxElementsInMemory="100" eternal="false" |
|
32 |
timeToIdleSeconds="1800" timeToLiveSeconds="1800" overflowToDisk="false" /> |
|
33 |
|
|
34 |
<cache name="oaistoresById" maxElementsInMemory="100" |
|
35 |
eternal="false" timeToIdleSeconds="1800" timeToLiveSeconds="1800" |
|
36 |
overflowToDisk="false" /> |
|
37 |
|
|
38 |
|
|
39 |
</ehcache> |
|
40 |
|
modules/dnet-oai-store-service/src/main/resources/eu/dnetlib/data/oai/store/xslt/addDMFBlock.xslt | ||
---|---|---|
1 |
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dc="http://purl.org/dc/elements/1.1/" version="1.0"> |
|
2 |
|
|
3 |
<xsl:template match="//*[local-name()='metadata']"> |
|
4 |
<metadata> |
|
5 |
<dmf> |
|
6 |
<xsl:apply-templates/> |
|
7 |
</dmf> |
|
8 |
</metadata> |
|
9 |
</xsl:template> |
|
10 |
|
|
11 |
<xsl:template match="@*|node()"> |
|
12 |
<xsl:copy> |
|
13 |
<xsl:apply-templates select="@*|node()"/> |
|
14 |
</xsl:copy> |
|
15 |
</xsl:template> |
|
16 |
</xsl:stylesheet> |
modules/dnet-oai-store-service/src/main/java/eu/dnetlib/data/oai/store/OAIStoreServiceImpl.java | ||
---|---|---|
1 |
package eu.dnetlib.data.oai.store; |
|
2 |
|
|
3 |
import javax.annotation.Resource; |
|
4 |
import javax.xml.ws.wsaddressing.W3CEndpointReference; |
|
5 |
|
|
6 |
import eu.dnetlib.data.oai.store.conf.OAIHelper; |
|
7 |
import org.springframework.beans.factory.annotation.Autowired; |
|
8 |
import org.springframework.beans.factory.annotation.Required; |
|
9 |
|
|
10 |
import eu.dnetlib.data.information.oai.publisher.info.MDFInfo; |
|
11 |
import eu.dnetlib.data.oai.store.conf.OAISetsCounter; |
|
12 |
import eu.dnetlib.data.oai.store.mongo.MongoPublisherStore; |
|
13 |
import eu.dnetlib.data.oai.store.mongo.MongoPublisherStoreDAO; |
|
14 |
import eu.dnetlib.data.oai.store.sync.OAIStoreSynchronizer; |
|
15 |
import eu.dnetlib.enabling.resultset.client.IterableResultSetClient; |
|
16 |
import eu.dnetlib.enabling.resultset.client.ResultSetClientFactory; |
|
17 |
import eu.dnetlib.enabling.tools.AbstractBaseService; |
|
18 |
import eu.dnetlib.enabling.tools.blackboard.NotificationHandler; |
|
19 |
|
|
20 |
public class OAIStoreServiceImpl extends AbstractBaseService implements OAIStoreService { |
|
21 |
|
|
22 |
/** |
|
23 |
* notification handler. |
|
24 |
*/ |
|
25 |
private NotificationHandler notificationHandler; |
|
26 |
|
|
27 |
@Autowired |
|
28 |
private MongoPublisherStoreDAO mongoPublisherStoreDAO; |
|
29 |
@Resource |
|
30 |
private OAIStoreSynchronizer synchronizer; |
|
31 |
@Resource(name = "oaiSetsCounter") |
|
32 |
private OAISetsCounter setsCounter; |
|
33 |
@Autowired |
|
34 |
private OAIHelper oaiHelper; |
|
35 |
|
|
36 |
@Resource |
|
37 |
private ResultSetClientFactory resultSetClientFactory; |
|
38 |
|
|
39 |
@Override |
|
40 |
public void feed(final W3CEndpointReference recordsEpr, final MDFInfo mdfInfo, final String dbName) { |
|
41 |
this.feed(recordsEpr, mdfInfo, "", dbName); |
|
42 |
} |
|
43 |
|
|
44 |
@Override |
|
45 |
public void feed(final W3CEndpointReference recordsEpr, final MDFInfo mdfInfo, final String recordSource, final String dbName) { |
|
46 |
IterableResultSetClient rsClient = resultSetClientFactory.getClient(recordsEpr); |
|
47 |
this.synchronizer.synchronize(rsClient, mdfInfo, recordSource, dbName, false, null, null); |
|
48 |
} |
|
49 |
|
|
50 |
@Override |
|
51 |
public void updateSetCounts(final String dbName) { |
|
52 |
this.setsCounter.updateCounts("", dbName, null, null); |
|
53 |
} |
|
54 |
|
|
55 |
@Override |
|
56 |
public void updateSetCounts(final MDFInfo mdfInfo, final String dbName) { |
|
57 |
this.setsCounter.updateCounts(mdfInfo, dbName, null, null); |
|
58 |
} |
|
59 |
|
|
60 |
@Override |
|
61 |
public void refreshConfiguration(final String dbName) { |
|
62 |
oaiHelper.loadConfiguration(dbName); |
|
63 |
} |
|
64 |
|
|
65 |
@Override |
|
66 |
public void ensureIndexes(final String dbName) { |
|
67 |
this.mongoPublisherStoreDAO.ensureIndex(dbName); |
|
68 |
} |
|
69 |
|
|
70 |
@Override |
|
71 |
public void ensureIndexes(final MDFInfo mdfInfo, final String dbName) { |
|
72 |
MongoPublisherStore s = this.mongoPublisherStoreDAO.getStore(mdfInfo.getSourceFormatName(), mdfInfo.getSourceFormatInterpretation(), |
|
73 |
mdfInfo.getSourceFormatLayout(), dbName); |
|
74 |
s.ensureIndices(); |
|
75 |
} |
|
76 |
|
|
77 |
@Override |
|
78 |
public void notify(final String subscriptionId, final String topic, final String isId, final String message) { |
|
79 |
getNotificationHandler().notified(subscriptionId, topic, isId, message); |
|
80 |
} |
|
81 |
|
|
82 |
public NotificationHandler getNotificationHandler() { |
|
83 |
return notificationHandler; |
|
84 |
} |
|
85 |
|
|
86 |
@Required |
|
87 |
public void setNotificationHandler(final NotificationHandler notificationHandler) { |
|
88 |
this.notificationHandler = notificationHandler; |
|
89 |
} |
|
90 |
|
|
91 |
public OAIStoreSynchronizer getSynchronizer() { |
|
92 |
return synchronizer; |
|
93 |
} |
|
94 |
|
|
95 |
public void setSynchronizer(final OAIStoreSynchronizer synchronizer) { |
|
96 |
this.synchronizer = synchronizer; |
|
97 |
} |
|
98 |
|
|
99 |
public OAISetsCounter getSetsCounter() { |
|
100 |
return setsCounter; |
|
101 |
} |
|
102 |
|
|
103 |
public void setSetsCounter(final OAISetsCounter setsCounter) { |
|
104 |
this.setsCounter = setsCounter; |
|
105 |
} |
|
106 |
|
|
107 |
public OAIHelper getOaiHelper() { |
|
108 |
return oaiHelper; |
|
109 |
} |
|
110 |
|
|
111 |
public void setOaiHelper(final OAIHelper oaiHelper) { |
|
112 |
this.oaiHelper = oaiHelper; |
|
113 |
} |
|
114 |
|
|
115 |
public MongoPublisherStoreDAO getMongoPublisherStoreDAO() { |
|
116 |
return mongoPublisherStoreDAO; |
|
117 |
} |
|
118 |
|
|
119 |
public void setMongoPublisherStoreDAO(final MongoPublisherStoreDAO mongoPublisherStoreDAO) { |
|
120 |
this.mongoPublisherStoreDAO = mongoPublisherStoreDAO; |
|
121 |
} |
|
122 |
|
|
123 |
public ResultSetClientFactory getResultSetClientFactory() { |
|
124 |
return resultSetClientFactory; |
|
125 |
} |
|
126 |
|
|
127 |
public void setResultSetClientFactory(final ResultSetClientFactory resultSetClientFactory) { |
|
128 |
this.resultSetClientFactory = resultSetClientFactory; |
|
129 |
} |
|
130 |
|
|
131 |
} |
modules/dnet-oai-store-service/src/main/java/eu/dnetlib/data/oai/store/DummyRecordChangeDetector.java | ||
---|---|---|
1 |
package eu.dnetlib.data.oai.store; |
|
2 |
|
|
3 |
|
|
4 |
/** |
|
5 |
* This is a basic dummy implementation that always returns true, regardless the actual content of the records to compare. |
|
6 |
* |
|
7 |
* @author alessia |
|
8 |
* |
|
9 |
*/ |
|
10 |
public class DummyRecordChangeDetector implements RecordChangeDetector { |
|
11 |
|
|
12 |
/** |
|
13 |
* |
|
14 |
* {@inheritDoc} |
|
15 |
* |
|
16 |
* @see eu.dnetlib.data.oai.store.RecordChangeDetector#differs(java.lang.String, java.lang.String) |
|
17 |
*/ |
|
18 |
@Override |
|
19 |
public boolean differs(final String record1, final String record2) { |
|
20 |
return true; |
|
21 |
} |
|
22 |
|
|
23 |
} |
modules/dnet-oai-store-service/src/main/java/eu/dnetlib/data/oai/store/PublisherStore.java | ||
---|---|---|
1 |
package eu.dnetlib.data.oai.store; |
|
2 |
|
|
3 |
import java.util.List; |
|
4 |
|
|
5 |
import eu.dnetlib.data.information.oai.publisher.PublisherField; |
|
6 |
import eu.dnetlib.data.information.oai.publisher.info.RecordInfo; |
|
7 |
import eu.dnetlib.miscutils.functional.UnaryFunction; |
|
8 |
|
|
9 |
/** |
|
10 |
* Interface for store used by the publisher. Different back-ends require different implementation. |
|
11 |
* |
|
12 |
* @author alessia |
|
13 |
* |
|
14 |
* @param <T> |
|
15 |
* class of the object that can be used to iterate results of a bulk request of records from the store. |
|
16 |
*/ |
|
17 |
public interface PublisherStore<T extends Cursor> { |
|
18 |
|
|
19 |
/** |
|
20 |
* Returns the identifier of this store. |
|
21 |
* |
|
22 |
* @return a String that identifies this store |
|
23 |
*/ |
|
24 |
String getId(); |
|
25 |
|
|
26 |
/** |
|
27 |
* Gets the metadata format of this store. |
|
28 |
* |
|
29 |
* @return String |
|
30 |
*/ |
|
31 |
String getMetadataFormat(); |
|
32 |
|
|
33 |
/** |
|
34 |
* Gets the interpretation of this store. |
|
35 |
* |
|
36 |
* @return String |
|
37 |
*/ |
|
38 |
String getInterpretation(); |
|
39 |
|
|
40 |
/** |
|
41 |
* Gets the layout of this store. |
|
42 |
* |
|
43 |
* @return String |
|
44 |
*/ |
|
45 |
String getLayout(); |
|
46 |
|
|
47 |
/** |
|
48 |
* Retrieves the record with the given identifier from this store. |
|
49 |
* |
|
50 |
* @param recordId |
|
51 |
* identifier of the record to retrieve |
|
52 |
* @return a RecordInfo instance representing the XML record |
|
53 |
*/ |
|
54 |
RecordInfo getRecord(final String recordId); |
|
55 |
|
|
56 |
/** |
|
57 |
* Retrieves the record with the given identifier from this store and apply the given unary function before delivering. |
|
58 |
* |
|
59 |
* @param recordId |
|
60 |
* identifier of the record to retrieve |
|
61 |
* @param unaryFunction |
|
62 |
* mapping from String to String |
|
63 |
* @return a RecordInfo instance representing the XML record |
|
64 |
*/ |
|
65 |
RecordInfo getRecord(final String recordId, final UnaryFunction<String, String> unaryFunction); |
|
66 |
|
|
67 |
/** |
|
68 |
* Retrieves the records matching the given query string. |
|
69 |
* |
|
70 |
* @param queryString |
|
71 |
* search criterion |
|
72 |
* @param bodyIncluded |
|
73 |
* false to get only identifiers, true to also get the body of records |
|
74 |
* @param limit |
|
75 |
* max number of records to return. 0 means no limit. |
|
76 |
* @return an instance of T that can be used to iterate over the results. |
|
77 |
*/ |
|
78 |
T getRecords(final String queryString, final boolean bodyIncluded, final int limit); |
|
79 |
|
|
80 |
/** |
|
81 |
* Retrieves the records matching the given query string and apply the given unary function before delivering. |
|
82 |
* |
|
83 |
* @param queryString |
|
84 |
* search criterion |
|
85 |
* @param unaryFunction |
|
86 |
* mapping from String to String |
|
87 |
* @param bodyIncluded |
|
88 |
* false to get only identifiers, true to also get the body of records |
|
89 |
* @param limit |
|
90 |
* max number of records to return. 0 means no limit. |
|
91 |
* @return an instance of T that can be used to iterate over the results. |
|
92 |
*/ |
|
93 |
T getRecords(final String queryString, final UnaryFunction<String, String> unaryFunction, final boolean bodyIncluded, final int limit); |
|
94 |
|
|
95 |
/** |
|
96 |
* Gets informaton about the indices available on this store. |
|
97 |
* |
|
98 |
* @return a List with information about the indices of this store. |
|
99 |
*/ |
|
100 |
List<PublisherField> getIndices(); |
|
101 |
|
|
102 |
/** |
|
103 |
* Ensures the indices on this store. |
|
104 |
*/ |
|
105 |
void ensureIndices(); |
|
106 |
|
|
107 |
/** |
|
108 |
* Feeds the store with the given records. |
|
109 |
* |
|
110 |
* @param records |
|
111 |
* XML records to store. |
|
112 |
* @param source |
|
113 |
* String that identifies the record source. |
|
114 |
* @return the number of stored records. |
|
115 |
*/ |
|
116 |
int feed(final Iterable<String> records, final String source); |
|
117 |
|
|
118 |
/** |
|
119 |
* Drops the content of the store. |
|
120 |
* |
|
121 |
*/ |
|
122 |
void drop(); |
|
123 |
|
|
124 |
/** |
|
125 |
* Drops the elements matching the query from the store. |
|
126 |
* |
|
127 |
* @param queryString |
|
128 |
*/ |
|
129 |
void drop(final String queryString); |
|
130 |
|
|
131 |
/** |
|
132 |
* Counts the number of records in this store. |
|
133 |
* |
|
134 |
* @return the size of the store. |
|
135 |
*/ |
|
136 |
int count(); |
|
137 |
|
|
138 |
/** |
|
139 |
* Counts the number of records in this store matching the query. |
|
140 |
* |
|
141 |
* @param queryString |
|
142 |
* query |
|
143 |
* @return the size of the store. |
|
144 |
*/ |
|
145 |
int count(final String queryString); |
|
146 |
|
|
147 |
} |
modules/dnet-oai-store-service/src/main/java/eu/dnetlib/data/oai/store/parser/PublisherRecordParser.java | ||
---|---|---|
1 |
package eu.dnetlib.data.oai.store.parser; |
|
2 |
|
|
3 |
import java.io.StringReader; |
|
4 |
import java.util.List; |
|
5 |
import java.util.Map.Entry; |
|
6 |
|
|
7 |
import com.google.common.base.Function; |
|
8 |
import com.google.common.collect.ArrayListMultimap; |
|
9 |
import com.google.common.collect.Iterables; |
|
10 |
import com.google.common.collect.Multimap; |
|
11 |
import eu.dnetlib.data.information.oai.publisher.PublisherField; |
|
12 |
import eu.dnetlib.data.information.oai.publisher.conf.OAIConfigurationExistReader; |
|
13 |
import org.apache.commons.lang.StringUtils; |
|
14 |
import org.apache.commons.logging.Log; |
|
15 |
import org.apache.commons.logging.LogFactory; |
|
16 |
import org.dom4j.Document; |
|
17 |
import org.dom4j.DocumentException; |
|
18 |
import org.dom4j.Node; |
|
19 |
import org.dom4j.io.SAXReader; |
|
20 |
|
|
21 |
/** |
|
22 |
* An instance of this class can parse an XML record and extract the information needed to store the record in a publisher store. |
|
23 |
* |
|
24 |
* |
|
25 |
* @author alessia |
|
26 |
* |
|
27 |
*/ |
|
28 |
public class PublisherRecordParser { |
|
29 |
|
|
30 |
private static final Log log = LogFactory.getLog(PublisherRecordParser.class); // NOPMD by marko on 11/24/08 5:02 PM |
|
31 |
|
|
32 |
/** |
|
33 |
* List of the indices of the target store. |
|
34 |
*/ |
|
35 |
private List<PublisherField> storeIndices; |
|
36 |
|
|
37 |
private final SAXReader saxReader = new SAXReader(); |
|
38 |
|
|
39 |
/** |
|
40 |
* Parses the record and returns a map where a key is the name of an index, the value is the value in the record at the xpath specificed |
|
41 |
* in this.storeIndices. |
|
42 |
* |
|
43 |
* @param record |
|
44 |
* the XML string to parse. |
|
45 |
* @return a Multimap describing the values to be indexed for this record. |
|
46 |
*/ |
|
47 |
@SuppressWarnings({ "unchecked", "rawtypes" }) |
|
48 |
public Multimap<String, String> parseRecord(final String record, final String source) { |
|
49 |
Multimap<String, String> recordProps = ArrayListMultimap.create(); |
|
50 |
try { |
|
51 |
Document doc = this.saxReader.read(new StringReader(record)); |
|
52 |
if(StringUtils.isNotBlank(source)) recordProps.put(OAIConfigurationExistReader.SET_FIELD, source); |
|
53 |
for (PublisherField field : this.storeIndices) { |
|
54 |
for (Entry<String, String> indexEntry : field.getSources().entries()) { |
|
55 |
// each xpath can return a list of nodes or strings, depending on the xpath |
|
56 |
List xPathResult = doc.selectNodes(indexEntry.getValue()); |
|
57 |
if ((xPathResult != null) && !xPathResult.isEmpty()) { |
|
58 |
if (containsStrings(xPathResult)) { |
|
59 |
recordProps.putAll(field.getFieldName(), xPathResult); |
|
60 |
} else { |
|
61 |
if (containsNodes(xPathResult)) { |
|
62 |
recordProps.putAll(field.getFieldName(), Iterables.transform(xPathResult, new Function<Object, String>() { |
|
63 |
|
|
64 |
@Override |
|
65 |
public String apply(final Object obj) { |
|
66 |
if (obj == null) return ""; |
|
67 |
Node node = (Node) obj; |
|
68 |
return node.getText(); |
|
69 |
} |
|
70 |
})); |
|
71 |
} |
|
72 |
} |
|
73 |
} |
|
74 |
} |
|
75 |
} |
|
76 |
|
|
77 |
} catch (DocumentException e) { |
|
78 |
log.fatal("Can't parse record"); |
|
79 |
recordProps = null; |
|
80 |
} |
|
81 |
return recordProps; |
|
82 |
|
|
83 |
} |
|
84 |
|
|
85 |
@SuppressWarnings("rawtypes") |
|
86 |
private boolean containsStrings(final List objects) { |
|
87 |
Object first = objects.get(0); |
|
88 |
return first instanceof String; |
|
89 |
} |
|
90 |
|
|
91 |
@SuppressWarnings("rawtypes") |
|
92 |
private boolean containsNodes(final List objects) { |
|
93 |
Object first = objects.get(0); |
|
94 |
return first instanceof Node; |
|
95 |
} |
|
96 |
|
|
97 |
public List<PublisherField> getStoreIndices() { |
|
98 |
return storeIndices; |
|
99 |
} |
|
100 |
|
|
101 |
public void setStoreIndices(final List<PublisherField> storeIndices) { |
|
102 |
this.storeIndices = storeIndices; |
|
103 |
} |
|
104 |
|
|
105 |
public SAXReader getSaxReader() { |
|
106 |
return saxReader; |
|
107 |
} |
|
108 |
|
|
109 |
public PublisherRecordParser(final List<PublisherField> storeIndices) { |
|
110 |
super(); |
|
111 |
this.storeIndices = storeIndices; |
|
112 |
} |
|
113 |
|
|
114 |
public PublisherRecordParser() { |
|
115 |
super(); |
|
116 |
// TODO Auto-generated constructor stub |
|
117 |
} |
|
118 |
|
|
119 |
} |
modules/dnet-oai-store-service/src/main/java/eu/dnetlib/data/oai/store/sync/OAIStoreSynchronizer.java | ||
---|---|---|
1 |
package eu.dnetlib.data.oai.store.sync; |
|
2 |
|
|
3 |
import java.util.concurrent.Callable; |
|
4 |
import javax.annotation.Resource; |
|
5 |
|
|
6 |
import eu.dnetlib.data.information.oai.publisher.OaiPublisherException; |
|
7 |
import eu.dnetlib.data.information.oai.publisher.OaiPublisherRuntimeException; |
|
8 |
import eu.dnetlib.data.information.oai.publisher.conf.OAIConfigurationExistReader; |
|
9 |
import eu.dnetlib.data.information.oai.publisher.info.MDFInfo; |
|
10 |
import eu.dnetlib.data.oai.store.mongo.MongoPublisherStore; |
|
11 |
import eu.dnetlib.data.oai.store.mongo.MongoPublisherStoreDAO; |
|
12 |
import org.apache.commons.logging.Log; |
|
13 |
import org.apache.commons.logging.LogFactory; |
|
14 |
import org.springframework.beans.factory.annotation.Autowired; |
|
15 |
|
|
16 |
public class OAIStoreSynchronizer { |
|
17 |
|
|
18 |
private static final Log log = LogFactory.getLog(OAIStoreSynchronizer.class); // NOPMD by marko on 11/24/08 5:02 PM |
|
19 |
/** |
|
20 |
* OAI Publisher configuration. |
|
21 |
*/ |
|
22 |
@Resource |
|
23 |
private OAIConfigurationExistReader configuration; |
|
24 |
|
|
25 |
@Autowired |
|
26 |
private MongoPublisherStoreDAO mongoPublisherStoreDAO; |
|
27 |
|
|
28 |
public void synchronize(final Iterable<String> records, |
|
29 |
final MDFInfo sourceMetadataFormat, |
|
30 |
final String recordSource, |
|
31 |
final String dbName, |
|
32 |
final boolean alwaysNewRecord, |
|
33 |
final Callable<?> callback, |
|
34 |
final Callable<?> failCallback) { |
|
35 |
try { |
|
36 |
log.info("Synchronizing content for oai on db " + dbName + " for metadata format: " + sourceMetadataFormat+" . Record source: "+recordSource); |
|
37 |
MongoPublisherStore store = this.getStore(sourceMetadataFormat, dbName, alwaysNewRecord); |
|
38 |
int count = store.feed(records, recordSource); |
|
39 |
log.info("Content synchronized: store " + store.getId() + " fed with " + count + " records"); |
|
40 |
executeCallback(callback); |
|
41 |
} catch (Exception e) { |
|
42 |
log.error(e); |
|
43 |
executeCallback(failCallback); |
|
44 |
} |
|
45 |
} |
|
46 |
|
|
47 |
/** |
|
48 |
* Gets the OAI store for the given source metadata format. If the store does not exists, then a new one is created. |
|
49 |
* |
|
50 |
* @param sourceMetadataFormat |
|
51 |
* MDFInfo about the metadata format of the store to get |
|
52 |
* @return a MongoPublisherStore instance |
|
53 |
*/ |
|
54 |
private MongoPublisherStore getStore(final MDFInfo sourceMetadataFormat, final String dbName, final boolean alwaysNewRecord) { |
|
55 |
this.mongoPublisherStoreDAO.setAlwaysNewRecord(alwaysNewRecord); |
|
56 |
MongoPublisherStore store = this.mongoPublisherStoreDAO.getStore(sourceMetadataFormat.getSourceFormatName(), |
|
57 |
sourceMetadataFormat.getSourceFormatInterpretation(), sourceMetadataFormat.getSourceFormatLayout(), dbName); |
|
58 |
if (store == null) { |
|
59 |
log.debug("Creating store for metadata format: \n" + sourceMetadataFormat + " in db: " + dbName); |
|
60 |
try { |
|
61 |
store = this.mongoPublisherStoreDAO.createStore(sourceMetadataFormat.getSourceFormatName(), sourceMetadataFormat.getSourceFormatInterpretation(), |
|
62 |
sourceMetadataFormat.getSourceFormatLayout(), dbName); |
|
63 |
log.debug("Created store with id: " + store.getId()); |
|
64 |
} catch (OaiPublisherException e) { |
|
65 |
throw new OaiPublisherRuntimeException(e); |
|
66 |
} |
|
67 |
} |
|
68 |
return store; |
|
69 |
} |
|
70 |
|
|
71 |
protected void executeCallback(final Callable<?> callback) { |
|
72 |
if (callback != null) { |
|
73 |
try { |
|
74 |
callback.call(); |
|
75 |
} catch (Exception e) { |
|
76 |
log.error("Error executing callback", e); |
|
77 |
} |
|
78 |
} |
|
79 |
} |
|
80 |
|
|
81 |
public OAIConfigurationExistReader getConfiguration() { |
|
82 |
return configuration; |
|
83 |
} |
|
84 |
|
|
85 |
public void setConfiguration(final OAIConfigurationExistReader configuration) { |
|
86 |
this.configuration = configuration; |
|
87 |
} |
|
88 |
|
|
89 |
} |
modules/dnet-oai-store-service/src/main/java/eu/dnetlib/data/oai/store/Cursor.java | ||
---|---|---|
1 |
package eu.dnetlib.data.oai.store; |
|
2 |
|
|
3 |
import eu.dnetlib.data.information.oai.publisher.info.RecordInfo; |
|
4 |
|
|
5 |
public interface Cursor extends Iterable<RecordInfo> { |
|
6 |
|
|
7 |
int count(); |
|
8 |
|
|
9 |
boolean isBodyIncluded(); |
|
10 |
|
|
11 |
void setBodyIncluded(boolean bodyIncluded); |
|
12 |
|
|
13 |
} |
modules/dnet-oai-store-service/src/main/java/eu/dnetlib/data/oai/store/RecordChangeDetector.java | ||
---|---|---|
1 |
package eu.dnetlib.data.oai.store; |
|
2 |
|
|
3 |
public interface RecordChangeDetector { |
|
4 |
|
|
5 |
/** |
|
6 |
* Checks if the two records have differences based on logics that vary on the actual implementor class. |
|
7 |
* |
|
8 |
* @param record1 |
|
9 |
* first record to compare |
|
10 |
* @param record2 |
|
11 |
* second record to compare |
|
12 |
* @return true if the two records differ based on the implementor's logics |
|
13 |
*/ |
|
14 |
boolean differs(final String record1, final String record2); |
|
15 |
} |
modules/dnet-oai-store-service/src/main/java/eu/dnetlib/data/oai/store/PublisherStoreDAO.java | ||
---|---|---|
1 |
package eu.dnetlib.data.oai.store; |
|
2 |
|
|
3 |
import java.util.List; |
|
4 |
|
|
5 |
import eu.dnetlib.data.information.oai.publisher.OaiPublisherException; |
|
6 |
|
|
7 |
public interface PublisherStoreDAO<X extends PublisherStore<T>, T extends Cursor> { |
|
8 |
|
|
9 |
/** |
|
10 |
* Lists all PublisherStore. |
|
11 |
* |
|
12 |
* @param dbName |
|
13 |
* name of the target database |
|
14 |
* |
|
15 |
* @return a List of PublisherStore instances. |
|
16 |
*/ |
|
17 |
List<X> listPublisherStores(final String dbName); |
|
18 |
|
|
19 |
/** |
|
20 |
* Gets the store with the given identifier. |
|
21 |
* |
|
22 |
* @param dbName |
|
23 |
* name of the target database |
|
24 |
* |
|
25 |
* @param storeId |
|
26 |
* identifier of the store to retrieve |
|
27 |
* @return a PublisherStore instance or null if there is no store with the given id. |
|
28 |
*/ |
|
29 |
X getStore(final String storeId, final String dbName); |
|
30 |
|
|
31 |
/** |
|
32 |
* Gets the store with the given properties. |
|
33 |
* |
|
34 |
* @param mdfName |
|
35 |
* name of the metadata format |
|
36 |
* @param mdfInterpretation |
|
37 |
* name of the metadata interpretation |
|
38 |
* @param mdfLayout |
|
39 |
* name of the metadata layout |
|
40 |
* @param dbName |
|
41 |
* name of the target database |
|
42 |
* @return a PublisherStore instance or null if there is no store with the given properties. |
|
43 |
*/ |
|
44 |
X getStore(final String mdfName, final String mdfInterpretation, final String mdfLayout, final String dbName); |
|
45 |
|
|
46 |
/** |
|
47 |
* Gets the store to be used as source to deliver records with the given metadata prefix. |
|
48 |
* |
|
49 |
* @param targetMetadataPrefix |
|
50 |
* prefix of the metadata format deliverable through this store |
|
51 |
* @param dbName |
|
52 |
* name of the target database |
|
53 |
* @return a PublisherStore instance or null if there is no store serving the given metadata prefix. |
|
54 |
*/ |
|
55 |
X getStoreFor(final String targetMetadataPrefix, final String dbName); |
|
56 |
|
|
57 |
/** |
|
58 |
* Create a PublisherStore with the given properties. |
|
59 |
* |
|
60 |
* @param mdfName |
|
61 |
* name of the metadata format |
|
62 |
* @param mdfInterpretation |
|
63 |
* name of the metadata interpretation |
|
64 |
* @param mdfLayout |
|
65 |
* name of the metadata layout |
|
66 |
* @param dbName |
|
67 |
* name of the target database |
|
68 |
* @return a PublisherStore instance whose identifier is automatically generated. |
|
69 |
* @throws OaiPublisherException |
|
70 |
* if there is already another PublisherStore with the given metadata format name, layout and interpretation. |
|
71 |
*/ |
|
72 |
X createStore(final String mdfName, final String mdfInterpretation, final String mdfLayout, final String dbName) throws OaiPublisherException; |
|
73 |
|
|
74 |
/** |
|
75 |
* Deletes the store with the given identifier. |
|
76 |
* |
|
77 |
* @param storeId |
|
78 |
* id of the store to delete |
|
79 |
* @param dbName |
|
80 |
* name of the target database |
|
81 |
* @return true if the store was deleted successfully, false otherwise (e.g., a store with the given id does not exist). |
|
82 |
*/ |
|
83 |
boolean deleteStore(final String storeId, final String dbName); |
|
84 |
|
|
85 |
/** |
|
86 |
* Deletes from the store with the given identifier the records belonging to the given set. |
|
87 |
* |
|
88 |
* @param storeId |
|
89 |
* id of the store to delete |
|
90 |
* @param dbName |
|
91 |
* name of the target database |
|
92 |
* @param set |
|
93 |
* name of the set |
|
94 |
* @return true if the records were deleted successfully, false otherwise (e.g., a store with the given id does not exist). |
|
95 |
*/ |
|
96 |
boolean deleteFromStore(final String storeId, final String dbName, final String set); |
|
97 |
|
|
98 |
/** |
|
99 |
* Deletes from the store with the given identifier the records belonging to the given set. |
|
100 |
* |
|
101 |
* @param mdfName |
|
102 |
* name of the metadata format |
|
103 |
* @param mdfInterpretation |
|
104 |
* name of the metadata interpretation |
|
105 |
* @param mdfLayout |
|
106 |
* name of the metadata layout |
|
107 |
* @param dbName |
|
108 |
* name of the target database |
|
109 |
* @param set |
|
110 |
* name of the set |
|
111 |
* @return true if the records were deleted successfully, false otherwise (e.g., a store with the given id does not exist). |
|
112 |
*/ |
|
113 |
boolean deleteFromStore(final String mdfName, final String mdfInterpretation, final String mdfLayout, final String dbName, final String set); |
|
114 |
|
|
115 |
/** |
|
116 |
* Deletes the store with the given properties. |
|
117 |
* |
|
118 |
* @param mdfName |
|
119 |
* name of the metadata format |
|
120 |
* @param mdfInterpretation |
|
121 |
* name of the metadata interpretation |
|
122 |
* @param mdfLayout |
|
123 |
* name of the metadata layout |
|
124 |
* @param dbName |
|
125 |
* name of the target database |
|
126 |
* @return true if the store was deleted successfully, false otherwise (e.g., a store with the given properties does not exist). |
|
127 |
*/ |
|
128 |
boolean deleteStore(final String mdfName, final String mdfInterpretation, final String mdfLayout, final String dbName); |
|
129 |
|
|
130 |
} |
modules/dnet-oai-store-service/src/main/java/eu/dnetlib/data/oai/store/sets/MongoSetCollection.java | ||
---|---|---|
1 |
package eu.dnetlib.data.oai.store.sets; |
|
2 |
|
|
3 |
import java.text.Normalizer; |
|
4 |
import java.util.List; |
|
5 |
|
|
6 |
import com.google.common.base.Function; |
|
7 |
import com.google.common.collect.Iterables; |
|
8 |
import com.google.common.collect.Lists; |
|
9 |
import com.mongodb.BasicDBObject; |
|
10 |
import com.mongodb.BasicDBObjectBuilder; |
|
11 |
import com.mongodb.DBObject; |
|
12 |
import com.mongodb.MongoClient; |
|
13 |
import com.mongodb.client.FindIterable; |
|
14 |
import com.mongodb.client.MongoCollection; |
|
15 |
import com.mongodb.client.model.Filters; |
|
16 |
import com.mongodb.client.model.FindOneAndReplaceOptions; |
|
17 |
import com.mongodb.client.model.FindOneAndUpdateOptions; |
|
18 |
import com.mongodb.client.model.IndexOptions; |
|
19 |
import eu.dnetlib.data.information.oai.publisher.info.SetInfo; |
|
20 |
import eu.dnetlib.data.information.oai.sets.SetCollection; |
|
21 |
import org.apache.commons.lang.StringEscapeUtils; |
|
22 |
import org.apache.commons.lang.StringUtils; |
|
23 |
import org.bson.conversions.Bson; |
|
24 |
import org.springframework.beans.factory.annotation.Autowired; |
|
25 |
|
|
26 |
public class MongoSetCollection implements SetCollection { |
|
27 |
|
|
28 |
public static String DEFAULT_SET = "OTHER"; |
|
29 |
|
|
30 |
@Autowired |
|
31 |
private MongoClient publisherMongoClient; |
|
32 |
private String setCollection = "sets"; |
|
33 |
private String setCountCollection = "setsCount"; |
|
34 |
|
|
35 |
public void ensureIndexes(final String dbName) { |
|
36 |
this.ensureIndexesOnSets(dbName); |
|
37 |
this.ensureIndexesOnCount(dbName); |
|
38 |
} |
|
39 |
|
|
40 |
@Override |
|
41 |
public List<SetInfo> getAllSets(final boolean enabledOnly, final String dbName) { |
|
42 |
FindIterable<DBObject> iter = null; |
|
43 |
if (!enabledOnly) { |
|
44 |
iter = this.getSetsCollection(dbName).find(); |
|
45 |
} else { |
|
46 |
Bson where = Filters.eq("enabled", true); |
|
47 |
iter = this.getSetsCollection(dbName).find(where); |
|
48 |
} |
|
49 |
return Lists.newArrayList(Iterables.transform(iter, new Function<DBObject, SetInfo>() { |
|
50 |
|
|
51 |
@Override |
|
52 |
public SetInfo apply(final DBObject dbObject) { |
|
53 |
return getSetFromDBObject(dbObject); |
|
54 |
} |
|
55 |
})); |
|
56 |
} |
|
57 |
|
|
58 |
@Override |
|
59 |
public boolean containSet(final String set, final String dbName) { |
|
60 |
Bson query = Filters.eq("spec", set); |
|
61 |
return this.getSetsCollection(dbName).count(query) != 0; |
|
62 |
} |
|
63 |
|
|
64 |
@Override |
|
65 |
public boolean containEnabledSet(final String set, final String publisherDBName) { |
|
66 |
Bson query = Filters.and(Filters.eq("spec", set), Filters.eq("enabled", true)); |
|
67 |
return this.getSetsCollection(publisherDBName).count(query) != 0; |
|
68 |
} |
|
69 |
|
|
70 |
@Override |
|
71 |
public String getSetQuery(final String set, final String dbName) { |
|
72 |
Bson query = Filters.eq("spec", set); |
|
73 |
BasicDBObject returnField = new BasicDBObject("query", 1); |
|
74 |
DBObject obj = this.getSetsCollection(dbName).find(query).projection(returnField).first(); |
|
75 |
return (String) obj.get("query"); |
|
76 |
} |
|
77 |
|
|
78 |
@Override |
|
79 |
public int count(final String setSpec, final String mdPrefix, final String dbName) { |
|
80 |
Bson query = Filters.and(Filters.eq("spec", setSpec), Filters.eq("mdPrefix", mdPrefix)); |
|
81 |
BasicDBObject returnField = new BasicDBObject("count", 1); |
|
82 |
DBObject obj = this.getSetsCountCollection(dbName).find(query).projection(returnField).first(); |
|
83 |
if (obj == null) return 0; |
|
84 |
return (Integer) obj.get("count"); |
|
85 |
} |
|
86 |
|
|
87 |
public void updateCounts(final String setSpec, final String mdPrefix, final int count, final String dbName) { |
|
88 |
BasicDBObject countUpdate = new BasicDBObject("$set", new BasicDBObject("count", count)); |
|
89 |
Bson query = Filters.and(Filters.eq("spec", setSpec), Filters.eq("mdPrefix", mdPrefix)); |
|
90 |
this.getSetsCountCollection(dbName).findOneAndUpdate(query, countUpdate, new FindOneAndUpdateOptions().upsert(true)); |
|
91 |
} |
|
92 |
|
|
93 |
public void upsertSet(final SetInfo setInfo, final boolean fromConfiguration, final String dbName) { |
|
94 |
DBObject obj = this.getObjectFromSet(setInfo); |
|
95 |
obj.put("fromConfiguration", fromConfiguration); |
|
96 |
//this.getSetsCollection(dbName).update(new BasicDBObject("spec", setInfo.getSetSpec()), obj, true, false); |
|
97 |
this.getSetsCollection(dbName).findOneAndReplace(Filters.eq("spec", setInfo.getSetSpec()), obj, new FindOneAndReplaceOptions().upsert(true)); |
|
98 |
} |
|
99 |
|
|
100 |
public String normalizeSetSpec(final String setName) { |
|
101 |
String s = StringEscapeUtils.unescapeXml(setName); |
|
102 |
s = Normalizer.normalize(s, Normalizer.Form.NFD); |
|
103 |
// replace spaces with underscores |
|
104 |
s = s.replaceAll(" ", "_"); |
|
105 |
// remove tilde, dots... over letters |
|
106 |
s = s.replaceAll("[\\p{InCombiningDiacriticalMarks}&&[^-_]]", ""); |
|
107 |
// change punctuation into an underscore |
|
108 |
s = s.replaceAll("[\\p{Punct}&&[^-_]]", "_"); |
|
109 |
// remove all non-word characters |
|
110 |
s = s.replaceAll("[\\W&&[^-_]]", ""); |
|
111 |
// Avoiding set '___' generated when we have "strange" set names such as those in cyrillic/ukrain |
|
112 |
// strips _ from the beginning and the end |
|
113 |
String stripped = StringUtils.strip(s, "_ "); |
|
114 |
if (StringUtils.isBlank(stripped)) { |
|
115 |
stripped = DEFAULT_SET; |
|
116 |
} |
|
117 |
return stripped; |
|
118 |
} |
|
119 |
|
|
120 |
public List<SetInfo> getConfiguredSets(final String dbName) { |
|
121 |
Bson query = Filters.eq("fromConfiguration", true); |
|
122 |
return this.findSets(query, dbName); |
|
123 |
} |
|
124 |
|
|
125 |
public List<SetInfo> getSetsFromData(final String dbName) { |
|
126 |
Bson query = Filters.eq("fromConfiguration", false); |
|
127 |
return this.findSets(query, dbName); |
|
128 |
} |
|
129 |
|
|
130 |
public void dropOAISets(final String dbName) { |
|
131 |
this.getSetsCountCollection(dbName).drop(); |
|
132 |
this.getSetsCollection(dbName).drop(); |
|
133 |
} |
|
134 |
|
|
135 |
public void dropSet(final String dbName, final String setSpec) { |
|
136 |
Bson query = Filters.eq("spec", setSpec); |
|
137 |
this.getSetsCollection(dbName).deleteMany(query); |
|
138 |
this.getSetsCountCollection(dbName).deleteMany(query); |
|
139 |
} |
|
140 |
|
|
141 |
public void dropConfigurationSets(final String dbName) { |
|
142 |
this.getSetsCollection(dbName).deleteMany(Filters.eq("fromConfiguration", true)); |
|
143 |
} |
|
144 |
|
|
145 |
protected List<SetInfo> findSets(final Bson query, final String dbName) { |
|
146 |
final FindIterable<DBObject> sets = this.getSetsCollection(dbName).find(query); |
|
147 |
List<SetInfo> res = Lists.newArrayList(); |
|
148 |
for (DBObject obj : sets) { |
|
149 |
res.add(this.getSetFromDBObject(obj)); |
|
150 |
} |
|
151 |
return res; |
|
152 |
} |
|
153 |
|
|
154 |
private SetInfo getSetFromDBObject(final DBObject obj) { |
|
155 |
SetInfo setInfo = new SetInfo(); |
|
156 |
setInfo.setEnabled((Boolean) obj.get("enabled")); |
|
157 |
setInfo.setQuery((String) obj.get("query")); |
|
158 |
setInfo.setSetDescription((String) obj.get("description")); |
|
159 |
setInfo.setSetName((String) obj.get("name")); |
|
160 |
setInfo.setSetSpec((String) obj.get("spec")); |
|
161 |
return setInfo; |
|
162 |
} |
|
163 |
|
|
164 |
private DBObject getObjectFromSet(final SetInfo s) { |
|
165 |
DBObject obj = BasicDBObjectBuilder.start("spec", s.getSetSpec()).add("name", s.getSetName()).add("description", s.getSetDescription()) |
|
166 |
.add("query", s.getQuery()).add("enabled", s.isEnabled()).get(); |
|
167 |
return obj; |
|
168 |
} |
|
169 |
|
|
170 |
private void ensureIndexesOnSets(final String dbName) { |
|
171 |
this.getSetsCollection(dbName).createIndex(new BasicDBObject("spec", 1), new IndexOptions().background(true)); |
|
172 |
this.getSetsCollection(dbName).createIndex(new BasicDBObject("fromConfiguration", 1), new IndexOptions().background(true)); |
|
173 |
} |
|
174 |
|
|
175 |
private void ensureIndexesOnCount(final String dbName) { |
|
176 |
BasicDBObject index = (BasicDBObject) BasicDBObjectBuilder.start("spec", 1).add("mdPrefix", 1).get(); |
|
177 |
this.getSetsCountCollection(dbName).createIndex(index, new IndexOptions().background(true)); |
|
178 |
} |
|
179 |
|
|
180 |
public MongoCollection<DBObject> getSetsCollection(final String dbName) { |
|
181 |
return this.getCollection(this.setCollection, dbName); |
|
182 |
} |
|
183 |
|
|
184 |
public MongoCollection<DBObject> getSetsCountCollection(final String dbName) { |
|
185 |
return this.getCollection(this.setCountCollection, dbName); |
|
186 |
} |
|
187 |
|
|
188 |
private MongoCollection<DBObject> getCollection(final String collectionName, final String dbName) { |
|
189 |
return publisherMongoClient.getDatabase(dbName).getCollection(collectionName, DBObject.class); |
|
190 |
} |
|
191 |
|
|
192 |
public String getSetCollection() { |
|
193 |
return setCollection; |
|
194 |
} |
|
195 |
|
|
196 |
public void setSetCollection(final String setCollection) { |
|
197 |
this.setCollection = setCollection; |
|
198 |
} |
|
199 |
|
|
200 |
public String getSetCountCollection() { |
|
201 |
return setCountCollection; |
|
202 |
} |
|
203 |
|
|
204 |
public void setSetCountCollection(final String setCountCollection) { |
|
205 |
this.setCountCollection = setCountCollection; |
|
206 |
} |
|
207 |
|
|
208 |
public MongoClient getPublisherMongoClient() { |
|
209 |
return publisherMongoClient; |
|
210 |
} |
|
211 |
|
|
212 |
public void setPublisherMongoClient(final MongoClient publisherMongoClient) { |
|
213 |
this.publisherMongoClient = publisherMongoClient; |
|
214 |
} |
|
215 |
|
|
216 |
} |
modules/dnet-oai-store-service/src/main/java/eu/dnetlib/data/oai/store/mongo/DNetOAIMongoCursor.java | ||
---|---|---|
1 |
package eu.dnetlib.data.oai.store.mongo; |
|
2 |
|
|
3 |
import java.util.Iterator; |
|
4 |
|
|
5 |
import com.google.common.collect.Lists; |
|
6 |
import com.mongodb.DBObject; |
|
7 |
import com.mongodb.client.MongoCursor; |
|
8 |
import eu.dnetlib.data.information.oai.publisher.info.RecordInfo; |
|
9 |
import eu.dnetlib.data.oai.store.Cursor; |
|
10 |
import eu.dnetlib.miscutils.functional.UnaryFunction; |
|
11 |
|
|
12 |
public class DNetOAIMongoCursor implements Cursor { |
|
13 |
|
|
14 |
/** |
|
15 |
* Underlying mongo cursor. |
|
16 |
*/ |
|
17 |
private MongoCursor<DBObject> dbCursor; |
|
18 |
private int size = 0; |
|
19 |
/** |
|
20 |
* Function to apply to records before delivering. |
|
21 |
*/ |
|
22 |
private UnaryFunction<String, String> function; |
|
23 |
|
|
24 |
/** |
|
25 |
* true if the RecordInfo returned by this Cursor must include the record body, false otherwise. |
|
26 |
*/ |
|
27 |
private boolean bodyIncluded; |
|
28 |
|
|
29 |
private RecordInfoGenerator recordInfoGenerator; |
|
30 |
private MetadataExtractor metadataExtractor; |
|
31 |
private ProvenanceExtractor provenanceExtractor; |
|
32 |
|
|
33 |
public DNetOAIMongoCursor() { |
|
34 |
super(); |
|
35 |
} |
|
36 |
|
|
37 |
public DNetOAIMongoCursor(final MongoCursor<DBObject> dbCursor, final boolean bodyIncluded, final RecordInfoGenerator recordInfoGenerator, |
|
38 |
final MetadataExtractor metadataExtractor) { |
|
39 |
this(dbCursor, null, bodyIncluded, recordInfoGenerator, metadataExtractor); |
|
40 |
} |
|
41 |
|
|
42 |
public DNetOAIMongoCursor(final MongoCursor<DBObject> dbCursor, final UnaryFunction<String, String> function, final boolean bodyIncluded, |
|
43 |
final RecordInfoGenerator recordInfoGenerator, final MetadataExtractor metadataExtractor) { |
|
44 |
super(); |
|
45 |
this.dbCursor = dbCursor; |
|
46 |
this.size = 0; |
|
47 |
this.function = function; |
|
48 |
this.bodyIncluded = bodyIncluded; |
|
49 |
this.recordInfoGenerator = recordInfoGenerator; |
|
50 |
this.metadataExtractor = metadataExtractor; |
|
51 |
} |
|
52 |
|
|
53 |
/** |
|
54 |
* |
|
55 |
* {@inheritDoc} |
|
56 |
*/ |
|
57 |
@Override |
|
58 |
public int count() { |
|
59 |
//I can do it because MongoCursor are always created from queries with "limit", so I do not expect the creation of the list to explode |
|
60 |
//to not exagerate, I'll get the size only if the current size is 0 |
|
61 |
if (size == 0) |
|
62 |
size = Lists.newArrayList(dbCursor).size(); |
|
63 |
return size; |
|
64 |
} |
|
65 |
|
|
66 |
/** |
|
67 |
* |
|
68 |
* {@inheritDoc} |
|
69 |
* |
|
70 |
* @see java.lang.Iterable#iterator() |
|
71 |
*/ |
|
72 |
@Override |
|
73 |
public Iterator<RecordInfo> iterator() { |
|
74 |
|
|
75 |
return new Iterator<RecordInfo>() { |
|
76 |
|
|
77 |
@Override |
|
78 |
public boolean hasNext() { |
|
79 |
return dbCursor.hasNext(); |
|
80 |
} |
|
81 |
|
|
82 |
@Override |
|
83 |
public RecordInfo next() { |
|
84 |
DBObject res = dbCursor.next(); |
|
85 |
RecordInfo info = recordInfoGenerator.transformDBObject(res, bodyIncluded); |
|
86 |
if ((function != null) && bodyIncluded && (info != null)) { |
|
87 |
info.setMetadata(function.evaluate(info.getMetadata())); |
|
88 |
} |
|
89 |
return info; |
|
90 |
} |
|
91 |
|
|
92 |
@Override |
|
93 |
public void remove() { |
|
94 |
throw new UnsupportedOperationException(); |
|
95 |
} |
|
96 |
|
|
97 |
}; |
|
98 |
} |
|
99 |
|
|
100 |
public UnaryFunction<String, String> getFunction() { |
|
101 |
return function; |
|
102 |
} |
|
103 |
|
|
104 |
public void setFunction(final UnaryFunction<String, String> function) { |
|
105 |
this.function = function; |
|
106 |
} |
|
107 |
|
|
108 |
public MongoCursor<DBObject> getDbCursor() { |
|
109 |
return dbCursor; |
|
110 |
} |
|
111 |
|
|
112 |
public void setDbCursor(final MongoCursor<DBObject> dbCursor) { |
|
113 |
this.dbCursor = dbCursor; |
|
114 |
} |
|
115 |
|
|
116 |
@Override |
|
117 |
public boolean isBodyIncluded() { |
|
118 |
return this.bodyIncluded; |
|
119 |
} |
|
120 |
|
|
121 |
@Override |
|
122 |
public void setBodyIncluded(final boolean bodyIncluded) { |
|
123 |
this.bodyIncluded = bodyIncluded; |
|
124 |
} |
|
125 |
|
|
126 |
public RecordInfoGenerator getRecordInfoGenerator() { |
|
127 |
return recordInfoGenerator; |
|
128 |
} |
|
129 |
|
|
130 |
public void setRecordInfoGenerator(final RecordInfoGenerator recordInfoGenerator) { |
|
131 |
this.recordInfoGenerator = recordInfoGenerator; |
|
132 |
} |
|
133 |
|
|
134 |
public MetadataExtractor getMetadataExtractor() { |
|
135 |
return metadataExtractor; |
|
136 |
} |
|
137 |
|
|
138 |
public void setMetadataExtractor(final MetadataExtractor metadataExtractor) { |
|
139 |
this.metadataExtractor = metadataExtractor; |
|
140 |
} |
|
141 |
|
|
142 |
public ProvenanceExtractor getProvenanceExtractor() { |
|
143 |
return provenanceExtractor; |
|
144 |
} |
|
145 |
|
|
146 |
public void setProvenanceExtractor(final ProvenanceExtractor provenanceExtractor) { |
|
147 |
this.provenanceExtractor = provenanceExtractor; |
|
148 |
} |
|
149 |
|
|
150 |
} |
modules/dnet-oai-store-service/src/main/java/eu/dnetlib/data/oai/store/mongo/MongoPublisherCacheHelper.java | ||
---|---|---|
1 |
package eu.dnetlib.data.oai.store.mongo; |
|
2 |
|
|
3 |
import java.util.List; |
|
4 |
import javax.annotation.Resource; |
|
5 |
|
|
6 |
import com.google.common.base.Function; |
|
7 |
import com.google.common.collect.Iterables; |
|
8 |
import com.google.common.collect.Lists; |
|
9 |
import com.mongodb.DBObject; |
|
10 |
import com.mongodb.MongoClient; |
|
11 |
import com.mongodb.WriteConcern; |
|
12 |
import com.mongodb.client.FindIterable; |
|
13 |
import com.mongodb.client.MongoDatabase; |
|
14 |
import com.mongodb.client.model.Filters; |
|
15 |
import eu.dnetlib.data.information.oai.publisher.conf.OAIConfigurationReader; |
|
16 |
import eu.dnetlib.data.oai.store.RecordChangeDetector; |
|
17 |
import eu.dnetlib.data.oai.store.sets.MongoSetCollection; |
|
18 |
import eu.dnetlib.functionality.cql.mongo.MongoCqlTranslator; |
|
19 |
import org.apache.commons.logging.Log; |
|
20 |
import org.apache.commons.logging.LogFactory; |
|
21 |
import org.springframework.beans.factory.annotation.Autowired; |
|
22 |
import org.springframework.cache.annotation.CacheEvict; |
|
23 |
import org.springframework.cache.annotation.Cacheable; |
|
24 |
|
|
25 |
/** |
|
26 |
* Created by alessia on 19/07/16. |
|
27 |
*/ |
|
28 |
public class MongoPublisherCacheHelper { |
|
29 |
|
|
30 |
private static final Log log = LogFactory.getLog(MongoPublisherCacheHelper.class); |
|
31 |
|
|
32 |
@Autowired |
|
33 |
private MongoClient publisherMongoClient; |
|
34 |
@Resource(name = "oaiConfigurationExistReader") |
|
35 |
private OAIConfigurationReader configuration; |
|
36 |
@Resource |
|
37 |
private MetadataExtractor metadataExtractor; |
|
38 |
@Resource |
|
39 |
private RecordInfoGenerator recordInfoGenerator; |
|
40 |
@Resource |
|
41 |
private RecordChangeDetector recordChangeDetector; |
|
42 |
|
|
43 |
|
|
44 |
public MongoDatabase getDB(final String dbName) { |
|
45 |
return this.publisherMongoClient.getDatabase(dbName).withWriteConcern(WriteConcern.JOURNALED); |
|
46 |
} |
|
47 |
|
|
48 |
@Cacheable(value="oaistores", key="#dbname") |
|
49 |
public List<MongoPublisherStore> listPublisherStores(final String dbName, final String metadataCollectionName, final boolean alwaysNewRecord, final MongoSetCollection mongoSetCollection) { |
|
50 |
log.info("Not using cache for listPublisherStores on "+dbName); |
|
51 |
final MongoDatabase db = getDB(dbName); |
|
52 |
final FindIterable<DBObject> stores = db.getCollection(metadataCollectionName, DBObject.class).find(); |
|
53 |
return Lists.newArrayList( |
|
54 |
Iterables.transform(stores, new Function<DBObject, MongoPublisherStore>() { |
|
55 |
@Override |
|
56 |
public MongoPublisherStore apply(final DBObject storeInfo) { |
|
57 |
return createFromDBObject(storeInfo, db, alwaysNewRecord, mongoSetCollection); |
|
58 |
} |
|
59 |
}) |
|
60 |
); |
|
61 |
} |
|
62 |
|
|
63 |
@Cacheable(value="oaistoresById", key="#storeId + #dbName", unless="#result == null") |
|
64 |
public MongoPublisherStore getStoreById(final String storeId, final String dbName, final String metadataCollectionName, final boolean alwaysNewRecord, final MongoSetCollection mongoSetCollection) { |
|
65 |
log.info(String.format("Not using cache for getStoreById: %s", storeId)); |
|
66 |
DBObject storeInfo = getDB(dbName).getCollection(metadataCollectionName, DBObject.class).find(Filters.eq("id", storeId)).first(); |
|
67 |
log.info("Got DBObject from mongo "+dbName+"."+metadataCollectionName+", id "+storeId+" is : "+storeInfo ); |
|
68 |
return this.createFromDBObject(storeInfo, getDB(dbName), alwaysNewRecord, mongoSetCollection); |
|
69 |
} |
|
70 |
|
|
71 |
@CacheEvict(value="oaistoresById", key = "#storeId + #dbName") |
|
72 |
public void deleteFromCache(String storeId, String dbName){ |
|
73 |
log.info("Evicting "+storeId+" for db "+dbName+ " from the cache"); |
|
74 |
} |
|
75 |
|
|
76 |
|
|
77 |
private MongoPublisherStore createFromDBObject(final DBObject storeInfo, final MongoDatabase db, final boolean alwaysNewRecord, final MongoSetCollection mongoSetCollection) { |
|
78 |
if (storeInfo == null){ |
|
79 |
log.error("cannot create MongoPublisherStore from null DBObject"); |
|
80 |
return null; |
|
81 |
} |
|
82 |
log.debug("Creating MongoPublisherStore from DBObject "+storeInfo.toString()); |
|
83 |
String storeId = (String) storeInfo.get("id"); |
|
84 |
String mdFormat = (String) storeInfo.get("metadataFormat"); |
|
85 |
String mdInterpretation = (String) storeInfo.get("interpretation"); |
|
86 |
String mdLayout = (String) storeInfo.get("layout"); |
|
87 |
MongoPublisherStore store = new MongoPublisherStore(storeId, mdFormat, mdInterpretation, mdLayout, db.getCollection(storeId, DBObject.class), |
|
88 |
this.configuration.getFields(mdFormat, mdInterpretation, mdLayout), recordInfoGenerator, this.configuration.getIdScheme(), |
|
89 |
this.configuration.getIdNamespace(), this.metadataExtractor, this.recordChangeDetector, alwaysNewRecord, db); |
|
90 |
store.setMongoSetCollection(mongoSetCollection); |
|
91 |
return store; |
|
92 |
} |
|
93 |
} |
modules/dnet-oai-store-service/src/main/java/eu/dnetlib/data/oai/store/mongo/RecordInfoGenerator.java | ||
---|---|---|
1 |
package eu.dnetlib.data.oai.store.mongo; |
|
2 |
|
|
3 |
import java.io.ByteArrayInputStream; |
|
4 |
import java.io.IOException; |
|
5 |
import java.io.StringReader; |
|
6 |
import java.util.Date; |
|
7 |
import java.util.List; |
|
8 |
import java.util.zip.ZipEntry; |
|
9 |
import java.util.zip.ZipInputStream; |
|
10 |
|
|
11 |
import javax.annotation.Resource; |
|
12 |
|
|
13 |
import org.apache.commons.io.IOUtils; |
|
14 |
import org.apache.commons.lang.StringEscapeUtils; |
|
15 |
import org.dom4j.Document; |
|
16 |
import org.dom4j.DocumentException; |
|
17 |
import org.dom4j.io.SAXReader; |
|
18 |
|
|
19 |
import com.google.common.collect.Sets; |
|
20 |
import com.mongodb.DBObject; |
|
21 |
|
|
22 |
import eu.dnetlib.data.information.oai.publisher.OaiPublisherRuntimeException; |
|
23 |
import eu.dnetlib.data.information.oai.publisher.conf.OAIConfigurationReader; |
|
24 |
import eu.dnetlib.data.information.oai.publisher.info.RecordInfo; |
|
25 |
|
|
26 |
/** |
|
27 |
* Helper class to generate a RecordInfo object from a Mongo DBObject. |
|
28 |
* |
|
29 |
* @author alessia |
|
30 |
* |
|
31 |
*/ |
|
32 |
public class RecordInfoGenerator { |
|
33 |
|
|
34 |
@Resource |
|
35 |
private MetadataExtractor metadataExtractor; |
|
36 |
@Resource |
|
37 |
private ProvenanceExtractor provenanceExtractor; |
|
38 |
|
|
39 |
@SuppressWarnings("unchecked") |
|
40 |
public RecordInfo transformDBObject(final DBObject object, final boolean includeBody) { |
|
41 |
if ((object == null) || object.keySet().isEmpty()) return null; |
|
42 |
String id = (String) object.get(OAIConfigurationReader.ID_FIELD); |
|
43 |
// need to escape the identifier, otherwise the XML breaks |
|
44 |
id = StringEscapeUtils.escapeXml(id); |
|
45 |
boolean deleted = (Boolean) object.get("deleted"); |
|
46 |
RecordInfo record = new RecordInfo(); |
|
47 |
record.setIdentifier(id); |
|
48 |
record.setInternalId(object.get("_id").toString()); |
|
49 |
record.setDatestamp((Date) object.get(OAIConfigurationReader.DATESTAMP_FIELD)); |
|
50 |
record.setDeleted(deleted); |
|
51 |
List<String> sets = (List<String>) object.get(OAIConfigurationReader.SET_FIELD); |
|
52 |
if (sets != null) { |
|
53 |
record.setSetspecs(Sets.newHashSet(sets)); |
|
54 |
} |
|
55 |
if (includeBody && !deleted) { |
|
56 |
String body = decompressRecord((byte[]) object.get(OAIConfigurationReader.BODY_FIELD)); |
|
57 |
final SAXReader reader = new SAXReader(); |
|
58 |
Document doc; |
|
59 |
try { |
|
60 |
doc = reader.read(new StringReader(body)); |
|
61 |
record.setMetadata(this.metadataExtractor.evaluate(doc)); |
|
62 |
record.setProvenance(this.provenanceExtractor.evaluate(doc)); |
|
63 |
} catch (DocumentException e) { |
|
64 |
throw new OaiPublisherRuntimeException(e); |
|
65 |
} |
|
66 |
} |
|
67 |
return record; |
|
68 |
|
|
69 |
} |
|
70 |
|
|
71 |
public String decompressRecord(final byte[] input) { |
|
72 |
|
|
73 |
try { |
|
74 |
ByteArrayInputStream bis = new ByteArrayInputStream(input); |
|
75 |
ZipInputStream zis = new ZipInputStream(bis); |
|
76 |
ZipEntry ze; |
|
77 |
ze = zis.getNextEntry(); |
|
78 |
if (ze== null) |
|
79 |
throw new OaiPublisherRuntimeException("cannot decompress null zip entry "); |
|
80 |
if (!ze.getName().equals(OAIConfigurationReader.BODY_FIELD)) |
|
81 |
throw new OaiPublisherRuntimeException("cannot decompress zip entry name :"+ze.getName()); |
|
82 |
return IOUtils.toString(zis); |
|
83 |
} catch (IOException e) { |
|
84 |
throw new OaiPublisherRuntimeException(e); |
|
85 |
} |
|
86 |
|
|
87 |
|
|
88 |
} |
|
89 |
|
|
90 |
public MetadataExtractor getMetadataExtractor() { |
|
91 |
return metadataExtractor; |
|
92 |
} |
|
93 |
|
|
94 |
public void setMetadataExtractor(final MetadataExtractor metadataExtractor) { |
|
95 |
this.metadataExtractor = metadataExtractor; |
|
96 |
} |
|
97 |
|
|
98 |
public ProvenanceExtractor getProvenanceExtractor() { |
|
99 |
return provenanceExtractor; |
|
100 |
} |
|
101 |
|
|
102 |
public void setProvenanceExtractor(final ProvenanceExtractor provenanceExtractor) { |
|
103 |
this.provenanceExtractor = provenanceExtractor; |
|
104 |
} |
|
105 |
} |
modules/dnet-oai-store-service/src/main/java/eu/dnetlib/data/oai/store/mongo/MongoPublisherStore.java | ||
---|---|---|
1 |
package eu.dnetlib.data.oai.store.mongo; |
|
2 |
|
|
3 |
import java.io.IOException; |
|
4 |
import java.util.Collection; |
|
5 |
import java.util.Date; |
|
6 |
import java.util.List; |
Also available in: Unified diff
codebase used to migrate to java8 the production system