Project

General

Profile

« Previous | Next » 

Revision 48526

created a branch for the new mdstore

View differences:

modules/dnet-data-services/branches/new-mdstore/src/main/java/eu/dnetlib/data/objectstore/gridFS/GridFSObjectstoreResultSetListener.java
1
package eu.dnetlib.data.objectstore.gridFS;
2

  
3
import com.mongodb.*;
4
import com.mongodb.gridfs.GridFS;
5
import com.mongodb.gridfs.GridFSDBFile;
6
import eu.dnetlib.enabling.resultset.listener.ResultSetListener;
7
import eu.dnetlib.rmi.common.ResultSetException;
8
import eu.dnetlib.rmi.data.ObjectStoreFile;
9
import org.apache.commons.logging.Log;
10
import org.apache.commons.logging.LogFactory;
11

  
12
/**
13
 * The listener interface for receiving gridFSObjectstoreResultSet events. The class that is interested in processing a
14
 * gridFSObjectstoreResultSet event implements this interface, and the object created with that class is registered with a component using
15
 * the component's <code>addGridFSObjectstoreResultSetListener<code> method. When
16
 * the gridFSObjectstoreResultSet event occurs, that object's appropriate
17
 * method is invoked.
18
 */
19
public class GridFSObjectstoreResultSetListener implements ResultSetListener<ObjectStoreFile> {
20

  
21
	/**
22
	 * The Constant log.
23
	 */
24
	private static final Log log = LogFactory.getLog(GridFSObjectstoreResultSetListener.class);
25

  
26
    private ObjectStoreFile nextElement = null;
27

  
28
	/**
29
	 * The from date.
30
	 */
31
	private Long fromDate;
32

  
33
	/**
34
	 * The until date.
35
	 */
36
	private Long untilDate;
37

  
38
	/**
39
	 * The records.
40
	 */
41
	private Iterable<String> records;
42

  
43
	/**
44
	 * The object store id.
45
	 */
46
	private String objectStoreID;
47

  
48
	/**
49
	 * The collection.
50
	 */
51
	private GridFS collection;
52

  
53
	/**
54
	 * The base uri.
55
	 */
56
	private String baseURI;
57

  
58
	/**
59
	 * The current cursor.
60
	 */
61
	private DBCursor currentCursor;
62

  
63
	public GridFSObjectstoreResultSetListener(final Long fromDate,
64
			final Long untilDate,
65
			final String objectStoreID,
66
			final GridFS collection,
67
			final String baseURI,
68
			final Iterable<String> records) {
69
		this.fromDate = fromDate;
70
		this.untilDate = untilDate;
71
		this.objectStoreID = objectStoreID;
72
		this.collection = collection;
73
		this.baseURI = baseURI;
74
		this.records = records;
75
		createCurrentCursor();
76
        constructNextElement();
77
    }
78

  
79

  
80
    private void constructNextElement() {
81
        if (currentCursor.hasNext()) {
82
            nextElement = ObjectStoreFileUtility.build((GridFSDBFile) currentCursor.next(), baseURI, objectStoreID);
83
        } else
84
            nextElement = null;
85
    }
86

  
87
	@Override
88
	public boolean hasNext() {
89
        return nextElement != null;
90
    }
91

  
92
	@Override
93
	public ObjectStoreFile next() throws ResultSetException {
94
        final ObjectStoreFile tmp = nextElement;
95
        constructNextElement();
96
        return tmp;
97
    }
98

  
99
	@Override
100
	public int getCount() {
101
		return currentCursor.itcount();
102
	}
103

  
104
	@Override
105
	public int getTotal() {
106
		return currentCursor.count();
107
	}
108

  
109
	/**
110
	 * Creates the current cursor.
111
	 */
112
	private void createCurrentCursor() {
113
		if (log.isDebugEnabled()) {
114
			log.debug(String.format("Staring query "));
115
		}
116

  
117
		DBObject query;
118
		if (records != null) {
119
			QueryBuilder qBuilder = QueryBuilder.start("metadata.id").in(records);
120
			query = qBuilder.get();
121
		} else if ((fromDate != null) && (untilDate != null)) {
122
			query = new BasicDBObject();
123
			query.put("$gt", fromDate.doubleValue());
124
			query.put("$lt", untilDate.doubleValue());
125
			if (currentCursor != null) {
126
				currentCursor.close();
127
			}
128
		} else
129
			throw new IllegalArgumentException("Missing parameters on Delivery must provide either from, to, or ObjectStoreIDs");
130
        currentCursor = collection.getFileList(new BasicDBObject("metadata.timestamp", query)).sort(new BasicDBObject("_id", 1)).addOption(Bytes.QUERYOPTION_NOTIMEOUT);
131
    }
132

  
133
	/**
134
	 * Gets the from date.
135
	 *
136
	 * @return the from date
137
	 */
138
	public Long getFromDate() {
139
		return fromDate;
140
	}
141

  
142
	/**
143
	 * Sets the from date.
144
	 *
145
	 * @param fromdate the new from date
146
	 */
147
	public void setFromDate(final Long fromdate) {
148
		this.fromDate = fromdate;
149
	}
150

  
151
	/**
152
	 * Gets the until date.
153
	 *
154
	 * @return the until date
155
	 */
156
	public Long getUntilDate() {
157
		return untilDate;
158
	}
159

  
160
	/**
161
	 * Sets the until date.
162
	 *
163
	 * @param untilDate the new until date
164
	 */
165
	public void setUntilDate(final Long untilDate) {
166
		this.untilDate = untilDate;
167
	}
168

  
169
	/**
170
	 * Gets the records.
171
	 *
172
	 * @return the records
173
	 */
174
	public Iterable<String> getRecords() {
175
		return records;
176
	}
177

  
178
	/**
179
	 * Sets the records.
180
	 *
181
	 * @param records the new records
182
	 */
183
	public void setRecords(final Iterable<String> records) {
184
		this.records = records;
185
	}
186

  
187
	/**
188
	 * Gets the collection.
189
	 *
190
	 * @return the collection
191
	 */
192
	public GridFS getCollection() {
193
		return collection;
194
	}
195

  
196
	/**
197
	 * Sets the collection.
198
	 *
199
	 * @param collection the new collection
200
	 */
201
	public void setCollection(final GridFS collection) {
202
		this.collection = collection;
203
	}
204

  
205
	/**
206
	 * Gets the base uri.
207
	 *
208
	 * @return the base uri
209
	 */
210
	public String getBaseURI() {
211
		return baseURI;
212
	}
213

  
214
	/**
215
	 * Sets the base uri.
216
	 *
217
	 * @param baseURI the new base uri
218
	 */
219
	public void setBaseURI(final String baseURI) {
220
		this.baseURI = baseURI;
221
	}
222

  
223
	/**
224
	 * Gets the object store id.
225
	 *
226
	 * @return the object store id
227
	 */
228
	public String getObjectStoreID() {
229
		return objectStoreID;
230
	}
231

  
232
	/**
233
	 * Sets the object store id.
234
	 *
235
	 * @param objectStoreID the new object store id
236
	 */
237
	public void setObjectStoreID(final String objectStoreID) {
238
		this.objectStoreID = objectStoreID;
239
	}
240

  
241
}
modules/dnet-data-services/branches/new-mdstore/src/main/java/eu/dnetlib/data/mdstore/modular/mongodb/utils/EnsureIndexJob.java
1
package eu.dnetlib.data.mdstore.modular.mongodb.utils;
2

  
3
import eu.dnetlib.data.mdstore.modular.MDStoreDescription;
4
import eu.dnetlib.data.mdstore.modular.connector.MDStoreDao;
5
import eu.dnetlib.data.mdstore.modular.mongodb.MongoMDStore;
6
import eu.dnetlib.rmi.data.MDStoreServiceException;
7
import org.apache.commons.logging.Log;
8
import org.apache.commons.logging.LogFactory;
9
import org.springframework.beans.factory.annotation.Required;
10

  
11
public class EnsureIndexJob {
12

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

  
15
	private boolean enabled = false;
16

  
17
	private MDStoreDao dao;
18

  
19
	protected void doExecute() {
20
		log.info("performing mdstore index check");
21

  
22
		try {
23
			for (MDStoreDescription mdstore : getDao().listMDStores()) {
24
				try {
25
					log.info("ensureindex for mdStoreId:" + mdstore.getId());
26
					((MongoMDStore) getDao().getMDStore(mdstore.getId())).ensureIndices();
27
				} catch (Throwable e) {
28
					log.warn("unable to reindex mdstore: " + mdstore.getId(), e);
29
				}
30
			}
31
		} catch (MDStoreServiceException e) {
32
			log.warn("unable to reindex mdstore ", e);
33
		}
34

  
35
		log.info("mdstore index check completed");
36
	}
37

  
38
	public MDStoreDao getDao() {
39
		return dao;
40
	}
41

  
42
	@Required
43
	public void setDao(final MDStoreDao dao) {
44
		this.dao = dao;
45
	}
46

  
47
	public boolean isEnabled() {
48
		return enabled;
49
	}
50

  
51
	@Required
52
	public void setEnabled(final boolean enabled) {
53
		this.enabled = enabled;
54
	}
55
}
modules/dnet-data-services/branches/new-mdstore/src/main/java/eu/dnetlib/data/mdstore/modular/mongodb/MongoOptionsFactory.java
1
package eu.dnetlib.data.mdstore.modular.mongodb;
2

  
3
import com.mongodb.MongoClientOptions;
4
import org.springframework.beans.BeansException;
5
import org.springframework.beans.factory.FactoryBean;
6

  
7
public class MongoOptionsFactory implements FactoryBean<MongoClientOptions> {
8

  
9
	private int connectionsPerHost;
10

  
11
	@Override
12
	public MongoClientOptions getObject() throws BeansException {
13
		return MongoClientOptions.builder().connectionsPerHost(connectionsPerHost).build();
14
	}
15

  
16
	@Override
17
	public Class<MongoClientOptions> getObjectType() {
18
		return MongoClientOptions.class;
19
	}
20

  
21
	@Override
22
	public boolean isSingleton() {
23
		return false;
24
	}
25

  
26
	public int getConnectionsPerHost() {
27
		return connectionsPerHost;
28
	}
29

  
30
	public void setConnectionsPerHost(int connectionsPerHost) {
31
		this.connectionsPerHost = connectionsPerHost;
32
	}
33

  
34
}
0 35

  
modules/dnet-data-services/branches/new-mdstore/src/main/java/eu/dnetlib/data/objectstore/gridFS/GridFSObjectStore.java
1
package eu.dnetlib.data.objectstore.gridFS;
2

  
3
import java.io.ByteArrayInputStream;
4
import java.io.IOException;
5
import java.io.InputStream;
6
import java.io.UnsupportedEncodingException;
7
import java.net.URLEncoder;
8
import java.util.Iterator;
9
import java.util.List;
10
import java.util.regex.Pattern;
11
import java.util.stream.Collectors;
12

  
13
import com.mongodb.BasicDBObject;
14
import com.mongodb.DBCursor;
15
import com.mongodb.DBObject;
16
import com.mongodb.gridfs.GridFS;
17
import com.mongodb.gridfs.GridFSDBFile;
18
import com.mongodb.gridfs.GridFSInputFile;
19
import eu.dnetlib.data.objectstore.ObjectStoreRecord;
20
import eu.dnetlib.data.objectstore.connector.ObjectStore;
21
import eu.dnetlib.enabling.resultset.listener.ResultSetListener;
22
import eu.dnetlib.enabling.tools.DnetStreamSupport;
23
import eu.dnetlib.rmi.data.MetadataObjectRecord;
24
import eu.dnetlib.rmi.data.ObjectStoreFile;
25
import eu.dnetlib.rmi.data.ObjectStoreFileNotFoundException;
26
import eu.dnetlib.rmi.data.ObjectStoreServiceException;
27
import org.apache.commons.logging.Log;
28
import org.apache.commons.logging.LogFactory;
29

  
30
// TODO: Auto-generated Javadoc
31

  
32
/**
33
 * The Class GridFSObjectStore.
34
 */
35

  
36
public class GridFSObjectStore implements ObjectStore {
37

  
38
	/**
39
	 * The Constant log.
40
	 */
41
	private static final Log log = LogFactory.getLog(GridFSObjectStore.class);
42
	/**
43
	 * The collection.
44
	 */
45
	private final GridFS collection;
46
	/**
47
	 * The id.
48
	 */
49
	private String id;
50
	/**
51
	 * The upsert.
52
	 */
53
	private boolean upsert;
54
	/**
55
	 * The base uri.
56
	 */
57
	private String baseURI;
58

  
59
	/**
60
	 * Instantiates a new grid fs object store.
61
	 *
62
	 * @param id         the id
63
	 * @param collection the collection
64
	 * @param upsert     the upsert
65
	 */
66
	public GridFSObjectStore(final String id, final GridFS collection, final boolean upsert) {
67
		this.id = id;
68
		this.setUpsert(upsert);
69
		this.collection = collection;
70

  
71
	}
72

  
73
	/*
74
	 * (non-Javadoc)
75
	 *
76
	 * @see eu.dnetlib.data.objectstore.modular.connector.ObjectStore#getId()
77
	 */
78
	@Override
79
	public String getId() {
80
		return id;
81
	}
82

  
83
	/*
84
	 * (non-Javadoc)
85
	 *
86
	 * @see eu.dnetlib.data.objectstore.modular.connector.ObjectStore#feedMetadataRecord(java.lang.Iterable, boolean)
87
	 */
88
	@Override
89
	public int feedMetadataRecord(final Iterable<MetadataObjectRecord> records, final boolean incremental) {
90
		long timestamp = System.currentTimeMillis();
91
		for (MetadataObjectRecord o : records) {
92
			if (o == null || o.getRecord() == null) {
93
				log.debug("Null object metadata record");
94
				continue;
95
			}
96

  
97
			GridFSInputFile currentFile = collection.createFile(new ByteArrayInputStream(o.getRecord().getBytes()));
98
			currentFile.setId(o.getId());
99
			BasicDBObject metadata = new BasicDBObject();
100
			metadata.put("id", o.getId());
101
			metadata.put("mime", o.getMime());
102
			metadata.put("timestamp", timestamp);
103
			try {
104
				String URI = baseURI + "?objectStore=" + URLEncoder.encode(id, "UTF-8") + "&objectId=" + URLEncoder.encode(o.getId(), "UTF-8");
105
				metadata.put("uri", URI);
106

  
107
			} catch (UnsupportedEncodingException e) {
108
				log.error("Got an exception during the feed ", e);
109
			}
110
			currentFile.setMetaData(metadata);
111
			currentFile.save();
112
		}
113
		return this.getSize();
114
	}
115

  
116
	/*
117
	 * (non-Javadoc)
118
	 *
119
	 * @see eu.dnetlib.data.objectstore.modular.connector.ObjectStore#feed(java.lang.Iterable, boolean)
120
	 */
121
	@Override
122
	public int feed(final Iterable<ObjectStoreRecord> records, final boolean incremental) {
123
		long timestamp = System.currentTimeMillis();
124
		int time = 0;
125
		for (ObjectStoreRecord o : records) {
126
			if (o == null || o.getInputStream() == null) {
127
				if (o != null) {
128
					log.debug("Null object " + o.getFileMetadata().toJSON());
129
				} else {
130
					log.debug("Null Object");
131
				}
132
				try {
133
					Thread.sleep(1000);
134
				} catch (InterruptedException e) {
135
					log.error(e);
136
				}
137
				continue;
138
			}
139
			if (alreadyExist(o.getFileMetadata().getObjectID())) {
140
				try {
141
					o.getInputStream().close();
142
				} catch (IOException e) {
143
					log.error("Error on closing inputStream ", e);
144
				}
145
				continue;
146
			}
147
			GridFSInputFile currentFile = collection.createFile(o.getInputStream());
148
			currentFile.setId(o.getFileMetadata().getObjectID());
149
			currentFile.setFilename(o.getFileMetadata().getObjectID());
150
			BasicDBObject metadata = new BasicDBObject();
151
			metadata.put("id", o.getFileMetadata().getObjectID());
152
			metadata.put("mime", o.getFileMetadata().getMimeType());
153
			metadata.put("originalObject", o.getFileMetadata().toJSON());
154
			metadata.put("timestamp", timestamp);
155
			try {
156
				String URI = baseURI + "?objectStore=" + URLEncoder.encode(id, "UTF-8") + "&objectId="
157
						+ URLEncoder.encode(o.getFileMetadata().getObjectID(), "UTF-8");
158
				metadata.put("uri", URI);
159

  
160
			} catch (UnsupportedEncodingException e) {
161
				log.error("Got an exception during the feed ", e);
162
			}
163
			currentFile.setMetaData(metadata);
164
			currentFile.save();
165
		}
166
		return getSize();
167
	}
168

  
169
	/*
170
	 * (non-Javadoc)
171
	 *
172
	 * @see eu.dnetlib.data.objectstore.modular.connector.ObjectStore#deliver(java.lang.Double, java.lang.Double)
173
	 */
174
	@Override
175
	public ResultSetListener deliver(final Long from, final Long until) {
176
		return new GridFSObjectstoreResultSetListener(from, until, id, collection, baseURI, null);
177
	}
178

  
179
	@Override
180
	public List<ObjectStoreFile> retrieveObjects(final int page, final int size) {
181
		final Iterator<DBObject> listObjects =
182
				collection.getFileList(new BasicDBObject()).sort(new BasicDBObject("_id", 1)).skip(page).limit(size).iterator();
183
		return DnetStreamSupport.generateStreamFromIterator(listObjects)
184
				.map(it -> ObjectStoreFileUtility.build((GridFSDBFile) it, baseURI, id))
185
				.collect(Collectors.toList());
186

  
187
	}
188

  
189
	/*
190
	 * (non-Javadoc)
191
	 *
192
	 * @see eu.dnetlib.data.objectstore.modular.connector.ObjectStore#deliverIds(java.lang.Iterable)
193
	 */
194
	@Override
195
	public ResultSetListener deliverIds(final Iterable<String> ids) {
196
		return new GridFSObjectstoreResultSetListener(null, null, id, collection, baseURI, ids);
197
	}
198

  
199
	/*
200
	 * (non-Javadoc)
201
	 *
202
	 * @see eu.dnetlib.data.objectstore.modular.connector.ObjectStore#getSize()
203
	 */
204
	@Override
205
	public int getSize() {
206
		return collection.getFileList().count();
207
	}
208

  
209
	/*
210
	 * (non-Javadoc)
211
	 *
212
	 * @see eu.dnetlib.data.objectstore.modular.connector.ObjectStore#deleteObject(java.lang.String)
213
	 */
214
	@Override
215
	public void deleteObject(final String objectId) {
216

  
217
	}
218

  
219
	/*
220
	 * (non-Javadoc)
221
	 *
222
	 * @see eu.dnetlib.data.objectstore.modular.connector.ObjectStore#getObject(java.lang.String)
223
	 */
224
	@Override
225
	public ObjectStoreFile getObject(final String recordId) {
226
		return null;
227
	}
228

  
229
	/*
230
	 * (non-Javadoc)
231
	 *
232
	 * @see eu.dnetlib.data.objectstore.modular.connector.ObjectStore#getInterpretation()
233
	 */
234
	@Override
235
	public String getInterpretation() {
236
		return (String) getMDStoreMetadata().get("interpretation");
237
	}
238

  
239
	/**
240
	 * Gets the MD store metadata.
241
	 *
242
	 * @return the MD store metadata
243
	 */
244
	public DBObject getMDStoreMetadata() {
245
		return collection.getDB().getCollection("metadataObjectStore").findOne(new BasicDBObject("obsId", Pattern.compile(getId())));
246
	}
247

  
248
	/**
249
	 * Gets the base uri.
250
	 *
251
	 * @return the base uri
252
	 */
253
	public String getBaseURI() {
254
		return baseURI;
255
	}
256

  
257
	/**
258
	 * Sets the base uri.
259
	 *
260
	 * @param baseURI the new base uri
261
	 */
262
	public void setBaseURI(final String baseURI) {
263
		this.baseURI = baseURI;
264

  
265
	}
266

  
267
	/**
268
	 * Checks if is upsert.
269
	 *
270
	 * @return true, if is upsert
271
	 */
272
	public boolean isUpsert() {
273
		return upsert;
274
	}
275

  
276
	/**
277
	 * Sets the upsert.
278
	 *
279
	 * @param upsert the new upsert
280
	 */
281
	public void setUpsert(final boolean upsert) {
282
		this.upsert = upsert;
283
	}
284

  
285
	/**
286
	 * Already exist.
287
	 *
288
	 * @param objectId the object id
289
	 * @return true, if successful
290
	 */
291
	@Override
292
	public boolean alreadyExist(final String objectId) {
293
		BasicDBObject query = new BasicDBObject("filename", objectId);
294
		List<GridFSDBFile> file = collection.find(query);
295
		return file != null && file.size() > 0;
296
	}
297

  
298
	@Override
299
	public ObjectStoreFile deliverObject(final String objectId) throws ObjectStoreServiceException {
300
		BasicDBObject query = new BasicDBObject("filename", objectId);
301
		final DBCursor fileList = collection.getFileList(query);
302

  
303
		if (fileList.hasNext()) return ObjectStoreFileUtility.build((GridFSDBFile) fileList.next(), baseURI, id);
304
		return null;
305
	}
306

  
307
	@Override
308
	public ObjectStoreFile deliverObjectFromMetadataIdentifier(String metadataId) throws ObjectStoreServiceException {
309
		BasicDBObject query = new BasicDBObject("filename", Pattern.compile(metadataId));
310
		final DBCursor fileList = collection.getFileList(query);
311
		if (fileList.hasNext()) return ObjectStoreFileUtility.build((GridFSDBFile) fileList.next(), baseURI, id);
312
		return null;
313
	}
314

  
315
	/**
316
	 * Check single item.
317
	 *
318
	 * @param objectId the object id
319
	 * @param file     the file
320
	 * @throws ObjectStoreFileNotFoundException the object store file not found exception
321
	 */
322
	private void checkSingleItem(final String objectId, final List<GridFSDBFile> file) throws ObjectStoreFileNotFoundException {
323
		if (file.isEmpty()) { throw new ObjectStoreFileNotFoundException(String.format("Object file not found with id: %s", objectId)); }
324
		if (file.size() > 1) { throw new IllegalStateException(String.format("More than one objects found with id: %s", objectId)); }
325
	}
326

  
327
	/*
328
	 * (non-Javadoc)
329
	 *
330
	 * @see eu.dnetlib.data.objectstore.modular.connector.ObjectStore#deliverStream(java.lang.String)
331
	 */
332
	@Override
333
	public InputStream deliverStream(final String objectId) throws ObjectStoreFileNotFoundException {
334
		BasicDBObject query = new BasicDBObject("filename", objectId);
335
		List<GridFSDBFile> file = collection.find(query);
336
		checkSingleItem(objectId, file);
337
		return file.get(0).getInputStream();
338
	}
339

  
340
	/*
341
	 * (non-Javadoc)
342
	 *
343
	 * @see
344
	 * eu.dnetlib.data.objectstore.modular.connector.ObjectStore#feedObjectRecord(eu.dnetlib.data.objectstore.modular.ObjectStoreRecord)
345
	 */
346
	@Override
347
	public String feedObjectRecord(final ObjectStoreRecord record) throws ObjectStoreServiceException {
348
		if (record == null || record.getFileMetadata() == null) { throw new ObjectStoreServiceException("Empty input Record"); }
349

  
350
		if (existIDStartsWith(record.getFileMetadata().getObjectID())) {
351
			log.debug("Object already exist ");
352
			if (record.getInputStream() != null) {
353
				try {
354
					record.getInputStream().close();
355
				} catch (IOException e) {
356
					log.debug("Exception happen in closing inputstream " + e);
357
					throw new ObjectStoreServiceException(e);
358
				}
359
			}
360
			ObjectStoreFile obj = deliverObject(record.getFileMetadata().getObjectID());
361
			return obj.getURI();
362
		}
363
		long timestamp = System.currentTimeMillis();
364
		String URI = "";
365

  
366
		if (record.getInputStream() == null) {
367
			throw new ObjectStoreServiceException("missing inputstream on record " + record.getFileMetadata().getObjectID());
368
		}
369

  
370
		GridFSInputFile currentFile = collection.createFile(record.getInputStream(), record.getFileMetadata().getObjectID());
371
		//		collection.createFile(record.getInputStream());
372
		//		currentFile.setId(record.getFileMetadata().getObjectID());
373
		//		currentFile.setFilename(record.getFileMetadata().getObjectID());
374
		BasicDBObject metadata = new BasicDBObject();
375
		metadata.put("id", record.getFileMetadata().getObjectID());
376
		metadata.put("mime", record.getFileMetadata().getMimeType());
377
		metadata.put("originalObject", record.getFileMetadata().toJSON());
378

  
379
		metadata.put("timestamp", timestamp);
380
		try {
381
			URI = baseURI + "?objectStore=" + URLEncoder.encode(id, "UTF-8") + "&objectId="
382
					+ URLEncoder.encode(record.getFileMetadata().getObjectID(), "UTF-8");
383
			metadata.put("uri", URI);
384
			currentFile.setMetaData(metadata);
385
			currentFile.save();
386

  
387
		} catch (Exception e) {
388
			throw new ObjectStoreServiceException(e);
389
		} finally {
390
			try {
391
				record.getInputStream().close();
392
			} catch (IOException e) {
393
				log.error(e);
394
			}
395
		}
396
		return URI;
397
	}
398

  
399
	/*
400
	 * (non-Javadoc)
401
	 *
402
	 * @see eu.dnetlib.data.objectstore.modular.connector.ObjectStore#existIDStartsWith(java.lang.String)
403
	 */
404
	@Override
405
	public boolean existIDStartsWith(final String startId) {
406
		BasicDBObject query = new BasicDBObject("id", startId);
407
		List<GridFSDBFile> file = collection.find(query);
408
		return file.size() > 0;
409
	}
410

  
411
	@Override
412
	public boolean dropContent() throws ObjectStoreServiceException {
413
		this.collection.remove(new BasicDBObject());
414
		return true;
415
	}
416
}
modules/dnet-data-services/branches/new-mdstore/src/main/java/eu/dnetlib/data/objectstore/gridFS/GridFSObjectstoreDaoImpl.java
1
package eu.dnetlib.data.objectstore.gridFS;
2

  
3
import java.util.List;
4
import java.util.regex.Pattern;
5
import java.util.stream.Collectors;
6

  
7
import com.mongodb.*;
8
import com.mongodb.gridfs.GridFS;
9
import eu.dnetlib.data.objectstore.connector.ObjectStore;
10
import eu.dnetlib.data.objectstore.connector.ObjectStoreDao;
11
import eu.dnetlib.enabling.tools.DnetStreamSupport;
12
import eu.dnetlib.rmi.data.ObjectStoreServiceException;
13
import org.bson.BSONObject;
14
import org.springframework.beans.factory.annotation.Required;
15

  
16
// TODO: Auto-generated Javadoc
17

  
18
/**
19
 * The Class GridFSObjectstoreDaoImpl.
20
 */
21

  
22
public class GridFSObjectstoreDaoImpl implements ObjectStoreDao {
23

  
24
	/**
25
	 * The Constant INTERPRETATION.
26
	 */
27
	public static final String INTERPRETATION = "interpretation";
28

  
29
	/**
30
	 * The Constant OBJECTSTOREMETADATANAME.
31
	 */
32
	private final static String OBJECTSTOREMETADATANAME = "metadataObjectStore";
33

  
34
	/**
35
	 * The Constant OBJECTSTOREIDFIELD.
36
	 */
37
	private final static String OBJECTSTOREIDFIELD = "obsId";
38

  
39
	/**
40
	 * The db.
41
	 */
42
	private DB db;
43

  
44
	/**
45
	 * The upsert.
46
	 */
47
	private boolean upsert;
48

  
49
	/**
50
	 * The object store resturi.
51
	 */
52
	private String objectStoreRESTURI;
53

  
54
	/**
55
	 * {@inheritDoc}
56
	 */
57
	@Override
58
	public ObjectStore getObjectStore(String obsId) {
59
		db.setWriteConcern(WriteConcern.SAFE);
60
		obsId = obsId.substring(0, 36);
61
		GridFSObjectStore objectStore = new GridFSObjectStore(obsId, new GridFS(db, obsId), this.upsert);
62
		objectStore.setBaseURI(objectStoreRESTURI);
63
		checkIndexes(obsId);
64
		return objectStore;
65
	}
66

  
67
	/**
68
	 * Check indexes.
69
	 *
70
	 * @param id the id
71
	 */
72
	private void checkIndexes(final String id) {
73
		DBCollection coll = db.getCollection(id + ".files");
74
		List<DBObject> indexInfo = coll.getIndexInfo();
75
		boolean hasTimestampIndex = false;
76
		for (DBObject info : indexInfo) {
77
			BSONObject boj = (BSONObject) info.get("key");
78
			if (boj.get("metadata.timestamp") != null) {
79
				hasTimestampIndex = true;
80
			}
81
		}
82
		if (!hasTimestampIndex) {
83
			coll.createIndex("metadata.timestamp");
84
		}
85
	}
86

  
87
	/**
88
	 * {@inheritDoc}
89
	 */
90
	@Override
91
	public List<String> listObjectStores() {
92
		DBCollection metadata = db.getCollection(OBJECTSTOREMETADATANAME);
93
		return DnetStreamSupport.generateStreamFromIterator(metadata.find().iterator())
94
				.map(object -> (String) object.get(OBJECTSTOREIDFIELD))
95
				.collect(Collectors.toList());
96
	}
97

  
98
	/**
99
	 * {@inheritDoc}
100
	 */
101
	@Override
102
	public boolean createObjectStore(final String obsId, final String interpretation, final String basePath) throws ObjectStoreServiceException {
103
		try {
104
			DBCollection coll = db.getCollection(OBJECTSTOREMETADATANAME);
105
			final BasicDBObject obj = new BasicDBObject();
106
			obj.put(OBJECTSTOREIDFIELD, obsId);
107
			obj.put(INTERPRETATION, interpretation);
108
			coll.save(obj);
109
		} catch (Throwable e) {
110
			throw new ObjectStoreServiceException("Error on create object store with id: " + obsId, e);
111
		}
112
		return true;
113
	}
114

  
115
	/**
116
	 * {@inheritDoc}
117
	 */
118
	@Override
119
	public boolean updateObjectStore(final String obsId, final String interpretation) {
120
		DBCollection coll = db.getCollection(OBJECTSTOREMETADATANAME);
121
		final BasicDBObject obj = new BasicDBObject();
122
		obj.put(OBJECTSTOREIDFIELD, obsId);
123
		obj.put(INTERPRETATION, interpretation);
124
		coll.update(new BasicDBObject(OBJECTSTOREIDFIELD, obsId), obj, true, false);
125
		coll.save(obj);
126
		return true;
127
	}
128

  
129
	/**
130
	 * {@inheritDoc}
131
	 */
132
	@Override
133
	public boolean deleteObjectStore(String obsId) {
134
		DBCollection coll = db.getCollection(OBJECTSTOREMETADATANAME);
135
		coll.remove(new BasicDBObject(OBJECTSTOREIDFIELD, obsId));
136
		obsId = obsId.substring(0, 36);
137
		GridFS objectStore = new GridFS(db, obsId);
138
		Pattern any = Pattern.compile(".");
139
		BasicDBObject query = new BasicDBObject("md5", any);
140
		objectStore.remove(query);
141
		return true;
142
	}
143

  
144
	@Override
145
	public boolean dropContent(final String obsId) throws ObjectStoreServiceException {
146
		return getObjectStore(obsId).dropContent();
147
	}
148

  
149
	/**
150
	 * Gets the db.
151
	 *
152
	 * @return the db
153
	 */
154
	public DB getDb() {
155
		return db;
156
	}
157

  
158
	/**
159
	 * Sets the db.
160
	 *
161
	 * @param db the new db
162
	 */
163
	@Required
164
	public void setDb(final DB db) {
165
		this.db = db;
166
	}
167

  
168
	/**
169
	 * Checks if is upsert.
170
	 *
171
	 * @return true, if is upsert
172
	 */
173
	public boolean isUpsert() {
174
		return upsert;
175
	}
176

  
177
	/**
178
	 * Sets the upsert.
179
	 *
180
	 * @param upsert the new upsert
181
	 */
182
	@Required
183
	public void setUpsert(final boolean upsert) {
184
		this.upsert = upsert;
185
	}
186

  
187
	/**
188
	 * Gets the object store resturi.
189
	 *
190
	 * @return the object store resturi
191
	 */
192
	public String getObjectStoreRESTURI() {
193
		return objectStoreRESTURI;
194
	}
195

  
196
	/**
197
	 * Sets the object store resturi.
198
	 *
199
	 * @param objectStoreRESTURI the new object store resturi
200
	 */
201
	@Required
202
	public void setObjectStoreRESTURI(final String objectStoreRESTURI) {
203
		this.objectStoreRESTURI = objectStoreRESTURI;
204
	}
205

  
206
}
modules/dnet-data-services/branches/new-mdstore/src/main/java/eu/dnetlib/data/objectstore/gridFS/MongoGridFSOptionsFactory.java
1
package eu.dnetlib.data.objectstore.gridFS;
2

  
3
import com.mongodb.MongoClientOptions;
4
import org.springframework.beans.BeansException;
5
import org.springframework.beans.factory.FactoryBean;
6

  
7
public class MongoGridFSOptionsFactory implements FactoryBean<MongoClientOptions> {
8

  
9
	private int connectionsPerHost;
10

  
11
	@Override
12
	public MongoClientOptions getObject() throws BeansException {
13
		return MongoClientOptions.builder().connectionsPerHost(connectionsPerHost).build();
14
	}
15

  
16
	@Override
17
	public Class<MongoClientOptions> getObjectType() {
18
		return MongoClientOptions.class;
19
	}
20

  
21
	@Override
22
	public boolean isSingleton() {
23
		return false;
24
	}
25

  
26
	public int getConnectionsPerHost() {
27
		return connectionsPerHost;
28
	}
29

  
30
	public void setConnectionsPerHost(int connectionsPerHost) {
31
		this.connectionsPerHost = connectionsPerHost;
32
	}
33

  
34
}
modules/dnet-data-services/branches/new-mdstore/src/main/java/eu/dnetlib/data/objectstore/ObjectBroker.java
1
package eu.dnetlib.data.objectstore;
2

  
3
import java.io.*;
4
import java.net.*;
5
import java.util.function.Function;
6

  
7
import eu.dnetlib.rmi.data.Protocols;
8
import org.apache.commons.logging.Log;
9
import org.apache.commons.logging.LogFactory;
10
import org.apache.commons.net.ftp.FTPClient;
11

  
12
/**
13
 * The Class ObjectBroker is responsible to retrieve content from URL.
14
 */
15
public class ObjectBroker implements Function<ObjectStoreRecord, ObjectStoreRecord> {
16

  
17
	private static final Log log = LogFactory.getLog(ObjectBroker.class);
18

  
19
	/**
20
	 * The protocol.
21
	 */
22
	private Protocols protocol;
23

  
24
	/**
25
	 * The login.
26
	 */
27
	private String login;
28

  
29
	/**
30
	 * The password.
31
	 */
32
	private String password;
33

  
34
	/**
35
	 * The mime.
36
	 */
37
	private String mime;
38

  
39
	/**
40
	 * Instantiates a new object broker.
41
	 *
42
	 * @param protocol the protocol
43
	 * @param login    the login
44
	 * @param password the password
45
	 * @param mime     the mime
46
	 */
47
	public ObjectBroker(final Protocols protocol, final String login, final String password, final String mime) {
48
		this.protocol = protocol;
49
		this.login = login;
50
		this.password = password;
51
		this.mime = mime;
52
	}
53

  
54
	/**
55
	 * Gets the protocol.
56
	 *
57
	 * @return the protocol
58
	 */
59
	public Protocols getProtocol() {
60
		return protocol;
61
	}
62

  
63
	/**
64
	 * Sets the protocol.
65
	 *
66
	 * @param protocol the new protocol
67
	 */
68
	public void setProtocol(final Protocols protocol) {
69
		this.protocol = protocol;
70
	}
71

  
72
	/**
73
	 * Gets the login.
74
	 *
75
	 * @return the login
76
	 */
77
	public String getLogin() {
78
		return login;
79
	}
80

  
81
	/**
82
	 * Sets the login.
83
	 *
84
	 * @param login the new login
85
	 */
86
	public void setLogin(final String login) {
87
		this.login = login;
88
	}
89

  
90
	/**
91
	 * Gets the password.
92
	 *
93
	 * @return the password
94
	 */
95
	public String getPassword() {
96
		return password;
97
	}
98

  
99
	/**
100
	 * Sets the password.
101
	 *
102
	 * @param password the new password
103
	 */
104
	public void setPassword(final String password) {
105
		this.password = password;
106
	}
107

  
108
	/**
109
	 * Gets the mime.
110
	 *
111
	 * @return the mime
112
	 */
113
	public String getMime() {
114
		return mime;
115
	}
116

  
117
	/**
118
	 * Sets the mime.
119
	 *
120
	 * @param mime the new mime
121
	 */
122
	public void setMime(final String mime) {
123
		this.mime = mime;
124
	}
125

  
126
	/*
127
	 * (non-Javadoc)
128
	 * 
129
	 * @see com.google.common.base.Function#apply(java.lang.Object)
130
	 */
131
	@Override
132
	public ObjectStoreRecord apply(final ObjectStoreRecord objectStorerecord) {
133
		if (objectStorerecord == null) return null;
134

  
135
		Protocols currentProtocol = (objectStorerecord.getFileMetadata().getAccessProtocol() == Protocols.None) ? protocol : objectStorerecord
136
				.getFileMetadata().getAccessProtocol();
137
		objectStorerecord.getFileMetadata().setAccessProtocol(currentProtocol);
138
		if ((objectStorerecord.getFileMetadata().getMimeType() == null) || (objectStorerecord.getFileMetadata().getMimeType().length() == 0)) {
139
			objectStorerecord.getFileMetadata().setMimeType(mime);
140
		}
141

  
142
		switch (currentProtocol) {
143
		case FTP:
144
			FTPClient client = new FTPClient();
145
			try {
146
				URI uri = new URI(objectStorerecord.getFileMetadata().getURI());
147
				client.connect(uri.getHost());
148
				if ((objectStorerecord.getFileMetadata().getUsernameAuth() != null) && (objectStorerecord.getFileMetadata().getUsernameAuth().length() > 0)) {
149
					client.login(objectStorerecord.getFileMetadata().getUsernameAuth(), objectStorerecord.getFileMetadata().getPasswordAuth());
150
				} else {
151
					client.login("ftp", "a@a");
152

  
153
				}
154

  
155
				final InputStream stream = client.retrieveFileStream(uri.getPath());
156
				objectStorerecord.setInputStream(stream);
157
				return objectStorerecord;
158

  
159
			} catch (URISyntaxException e2) {
160
				log.error(e2);
161
				return null;
162
			} catch (SocketException e) {
163
				log.error(e);
164
			} catch (IOException e) {
165
				log.error(e);
166
				return null;
167
			}
168

  
169
		case HTTP:
170
			try {
171
				HttpURLConnection conn = (HttpURLConnection) new URL(objectStorerecord.getFileMetadata().getURI()).openConnection();
172
				InputStream in;
173
				int http_status;
174
				try {
175

  
176
					http_status = conn.getResponseCode();
177

  
178
					if ((http_status / 100) == 3) {
179
						String newURL = conn.getHeaderField("Location");
180
						conn.disconnect();
181
						conn = (HttpURLConnection) new URL(newURL).openConnection();
182
						http_status = conn.getResponseCode();
183
						if ((http_status / 100) != 2) return null;
184
					}
185
					in = conn.getInputStream();
186
					objectStorerecord.setInputStream(in);
187
					return objectStorerecord;
188
				} catch (Exception e) {
189
					log.error(e);
190
					return null;
191
				}
192
			} catch (MalformedURLException e1) {
193
				log.error(e1);
194
				return null;
195
			} catch (IOException e1) {
196
				log.error(e1);
197
				return null;
198
			}
199

  
200
		case File_System:
201
			File f = new File(objectStorerecord.getFileMetadata().getURI());
202
			try {
203
				InputStream myiInputStream = new FileInputStream(f);
204
				objectStorerecord.setInputStream(myiInputStream);
205
				return objectStorerecord;
206
			} catch (FileNotFoundException e) {
207
				try {
208
					Thread.sleep(5000);
209
					InputStream myiInputStream = new FileInputStream(f);
210
					objectStorerecord.setInputStream(myiInputStream);
211
					return objectStorerecord;
212
				} catch (Exception e1) {
213
					log.error(e1);
214
					return null;
215
				}
216
			}
217
		default:
218
			break;
219
		}
220

  
221
		return null;
222

  
223
	}
224

  
225
}
modules/dnet-data-services/branches/new-mdstore/src/main/java/eu/dnetlib/data/objectstore/ObjectStoreRecord.java
1
package eu.dnetlib.data.objectstore;
2

  
3
import java.io.InputStream;
4

  
5
import eu.dnetlib.rmi.data.ObjectStoreFile;
6

  
7
/**
8
 * The Class ObjectStoreRecord is a serialization of the object to be ingested in the objectStore
9
 * metadata + inputstream of the data.
10
 */
11
public class ObjectStoreRecord {
12

  
13
	/**
14
	 * The file metadata.
15
	 */
16
	private ObjectStoreFile fileMetadata;
17

  
18
	/**
19
	 * The input stream.
20
	 */
21
	private InputStream inputStream;
22

  
23
	/**
24
	 * Gets the input stream.
25
	 *
26
	 * @return the input stream
27
	 */
28
	public InputStream getInputStream() {
29
		return inputStream;
30
	}
31

  
32
	/**
33
	 * Sets the input stream.
34
	 *
35
	 * @param inputStream the new input stream
36
	 */
37
	public void setInputStream(final InputStream inputStream) {
38
		this.inputStream = inputStream;
39
	}
40

  
41
	/**
42
	 * Gets the file metadata.
43
	 *
44
	 * @return the file metadata
45
	 */
46
	public ObjectStoreFile getFileMetadata() {
47
		return fileMetadata;
48
	}
49

  
50
	/**
51
	 * Sets the file metadata.
52
	 *
53
	 * @param fileMetadata the new file metadata
54
	 */
55
	public void setFileMetadata(final ObjectStoreFile fileMetadata) {
56
		this.fileMetadata = fileMetadata;
57
	}
58

  
59
}
modules/dnet-data-services/branches/new-mdstore/src/main/java/eu/dnetlib/data/objectstore/gridFS/ObjectStoreFileUtility.java
1
package eu.dnetlib.data.objectstore.gridFS;
2

  
3
import java.io.UnsupportedEncodingException;
4
import java.net.URLEncoder;
5
import java.util.function.Function;
6

  
7
import com.mongodb.DBObject;
8
import com.mongodb.gridfs.GridFSDBFile;
9
import eu.dnetlib.rmi.data.ObjectStoreFile;
10
import eu.dnetlib.rmi.data.Protocols;
11
import org.apache.commons.logging.Log;
12
import org.apache.commons.logging.LogFactory;
13

  
14
/**
15
 * The Class ObjectStoreFileBuilder generates an objectStoreFile bean
16
 */
17
public class ObjectStoreFileUtility {
18

  
19
	private static final int KB_SIZE = 1024;
20

  
21
	/**
22
	 * The Constant log.
23
	 */
24
	private static final Log log = LogFactory.getLog(ObjectStoreFileUtility.class);
25

  
26
	/**
27
	 * Builds the.
28
	 *
29
	 * @param input         the input File
30
	 * @param baseURI       the base URI to associate to the metadata
31
	 * @param objectStoreID The objectStoreID the input file
32
	 * @return the object store file
33
	 */
34

  
35
	public static ObjectStoreFile build(final GridFSDBFile input, final String baseURI, final String objectStoreID) {
36
		DBObject metadata = input.getMetaData();
37
		String originalFile = (String) metadata.get("originalObject");
38
		ObjectStoreFile original = ObjectStoreFile.createObject(originalFile);
39
		ObjectStoreFile newFile = new ObjectStoreFile();
40
		newFile.setObjectID((String) metadata.get("id"));
41
		newFile.setAccessProtocol(Protocols.HTTP);
42
		newFile.setMimeType((String) metadata.get("mime"));
43
		newFile.setMd5Sum((String) input.get("md5"));
44
		newFile.setFileSizeKB(input.getLength() / KB_SIZE);
45
		if (originalFile != null) {
46
			newFile.setMetadataRelatedID(original.getMetadataRelatedID());
47
			if (original.getDownloadedURL() == null || original.getDownloadedURL().length() == 0) {
48
				newFile.setDownloadedURL(original.getURI());
49
			} else {
50
				newFile.setDownloadedURL(original.getDownloadedURL());
51
			}
52

  
53
		}
54
		try {
55
			newFile.setURI(baseURI + "?objectStore=" + URLEncoder.encode(objectStoreID, "UTF-8") + "&objectId="
56
					+ URLEncoder.encode(newFile.getObjectID(), "UTF-8"));
57
		} catch (UnsupportedEncodingException e) {
58
			log.error("Error on Build objectStoreFile ", e);
59
		}
60
		return newFile;
61
	}
62

  
63
	public static Function<GridFSDBFile, String> asJSON(final String baseURI, final String objectStoreID) {
64
		return input -> build(input, baseURI, objectStoreID).toJSON();
65

  
66
	}
67
}
modules/dnet-data-services/branches/new-mdstore/src/main/java/eu/dnetlib/data/objectstore/ModularObjectStoreDeliver.java
1
package eu.dnetlib.data.objectstore;
2

  
3
import java.io.InputStream;
4

  
5
import eu.dnetlib.data.objectstore.connector.ObjectStoreDao;
6
import eu.dnetlib.enabling.resultset.client.ResultSetClient;
7
import eu.dnetlib.enabling.resultset.factory.ResultSetFactory;
8
import eu.dnetlib.rmi.common.ResultSet;
9
import eu.dnetlib.rmi.data.ObjectStoreFile;
10
import eu.dnetlib.rmi.data.ObjectStoreServiceException;
11
import org.springframework.beans.factory.annotation.Autowired;
12
import org.springframework.beans.factory.annotation.Required;
13

  
14
/**
15
 * The Class ModularObjectStoreDeliver is responsible of delivering data from the object Store.
16
 */
17
public class ModularObjectStoreDeliver {
18

  
19
	/**
20
	 * The dao.
21
	 */
22
	private ObjectStoreDao dao;
23

  
24
	/**
25
	 * The result set factory.
26
	 */
27

  
28
	@Autowired
29
	private ResultSetFactory resultSetFactory;
30

  
31
	/**
32
	 * Gets the dao.
33
	 *
34
	 * @return the dao
35
	 */
36
	public ObjectStoreDao getDao() {
37
		return dao;
38
	}
39

  
40
	/**
41
	 * Sets the dao.
42
	 *
43
	 * @param dao the new dao
44
	 */
45
	@Required
46
	public void setDao(final ObjectStoreDao dao) {
47
		this.dao = dao;
48
	}
49

  
50
	/**
51
	 * Deliver.
52
	 *
53
	 * @param objectStoreID the object store id
54
	 * @param from          the from
55
	 * @param until         the until
56
	 * @return the w3 c endpoint reference
57
	 * @throws ObjectStoreServiceException
58
	 */
59
	public ResultSet<ObjectStoreFile> deliver(final String objectStoreID, final Long from, final Long until) throws ObjectStoreServiceException {
60
		return resultSetFactory.createResultSet(dao.getObjectStore(objectStoreID).deliver(from, until));
61
	}
62

  
63
	/**
64
	 * Deliver ids.
65
	 *
66
	 * @param objectStoreID the object store id
67
	 * @param eprId         the epr id
68
	 * @return the w3 c endpoint reference
69
	 * @throws ObjectStoreServiceException
70
	 */
71
	public ResultSet<ObjectStoreFile> deliverIds(final String objectStoreID, final ResultSet<String> eprId) throws ObjectStoreServiceException {
72

  
73
		final ResultSetClient resultSetClient = resultSetFactory.getResultSetClient();
74
		Iterable<String> ids = resultSetClient.iter(eprId, String.class);
75
		return resultSetFactory.createResultSet(dao.getObjectStore(objectStoreID).deliverIds(ids));
76
	}
77

  
78
	/**
79
	 * Exist id starts with.
80
	 *
81
	 * @param obsId   the obs id
82
	 * @param startId the start id
83
	 * @return true, if successful
84
	 * @throws ObjectStoreServiceException
85
	 */
86
	public boolean existIDStartsWith(final String obsId, final String startId) throws ObjectStoreServiceException {
87
		return dao.getObjectStore(obsId).existIDStartsWith(startId);
88
	}
89

  
90
	/**
91
	 * Deliver object.
92
	 *
93
	 * @param objectStoreID the object store id
94
	 * @param objectId      the object id
95
	 * @return the object store file
96
	 * @throws ObjectStoreServiceException
97
	 */
98
	public ObjectStoreFile deliverObject(final String objectStoreID, final String objectId) throws ObjectStoreServiceException {
99
		return dao.getObjectStore(objectStoreID).deliverObject(objectId);
100
	}
101

  
102
	/**
103
	 * Deliver stream.
104
	 *
105
	 * @param objectStoreID the object store id
106
	 * @param objectId      the object id
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff