Revision 6362
Added by ben leinfelder over 13 years ago
test/edu/ucsb/nceas/metacat/dataone/CrudServiceTest.java | ||
---|---|---|
1 |
/** |
|
2 |
* '$RCSfile$' |
|
3 |
* Copyright: 2010 Regents of the University of California and the |
|
4 |
* National Center for Ecological Analysis and Synthesis |
|
5 |
* Purpose: To test the Access Controls in metacat by JUnit |
|
6 |
* |
|
7 |
* '$Author: berkley $' |
|
8 |
* '$Date: 2010-05-03 14:26:08 -0700 (Fri, 14 Aug 2009) $' |
|
9 |
* '$Revision: 5027 $' |
|
10 |
* |
|
11 |
* This program is free software; you can redistribute it and/or modify |
|
12 |
* it under the terms of the GNU General Public License as published by |
|
13 |
* the Free Software Foundation; either version 2 of the License, or |
|
14 |
* (at your option) any later version. |
|
15 |
* |
|
16 |
* This program is distributed in the hope that it will be useful, |
|
17 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
18 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
19 |
* GNU General Public License for more details. |
|
20 |
* |
|
21 |
* You should have received a copy of the GNU General Public License |
|
22 |
* along with this program; if not, write to the Free Software |
|
23 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
24 |
*/ |
|
25 |
|
|
26 |
package edu.ucsb.nceas.metacat.dataone; |
|
27 |
|
|
28 |
import java.io.InputStream; |
|
29 |
import java.io.StringBufferInputStream; |
|
30 |
import java.security.MessageDigest; |
|
31 |
import java.util.Date; |
|
32 |
|
|
33 |
import junit.framework.Test; |
|
34 |
import junit.framework.TestSuite; |
|
35 |
|
|
36 |
import org.apache.commons.io.IOUtils; |
|
37 |
import org.dataone.client.ObjectFormatCache; |
|
38 |
import org.dataone.service.exceptions.BaseException; |
|
39 |
import org.dataone.service.types.AuthToken; |
|
40 |
import org.dataone.service.types.Checksum; |
|
41 |
import org.dataone.service.types.ChecksumAlgorithm; |
|
42 |
import org.dataone.service.types.DescribeResponse; |
|
43 |
import org.dataone.service.types.Identifier; |
|
44 |
import org.dataone.service.types.Log; |
|
45 |
import org.dataone.service.types.LogEntry; |
|
46 |
import org.dataone.service.types.NodeReference; |
|
47 |
import org.dataone.service.types.ObjectFormat; |
|
48 |
import org.dataone.service.types.ObjectInfo; |
|
49 |
import org.dataone.service.types.ObjectList; |
|
50 |
import org.dataone.service.types.Subject; |
|
51 |
import org.dataone.service.types.SystemMetadata; |
|
52 |
|
|
53 |
import edu.ucsb.nceas.MCTestCase; |
|
54 |
import edu.ucsb.nceas.metacat.MetaCatServlet; |
|
55 |
import edu.ucsb.nceas.metacat.client.rest.MetacatRestClient; |
|
56 |
import edu.ucsb.nceas.metacat.properties.PropertyService; |
|
57 |
import edu.ucsb.nceas.metacat.service.SessionService; |
|
58 |
import edu.ucsb.nceas.metacat.util.SessionData; |
|
59 |
|
|
60 |
/** |
|
61 |
* A JUnit test for testing the dataone CrudService class |
|
62 |
*/ |
|
63 |
public class CrudServiceTest extends MCTestCase |
|
64 |
{ |
|
65 |
private int createCount = 0; |
|
66 |
|
|
67 |
/** |
|
68 |
* consstructor for the test |
|
69 |
*/ |
|
70 |
public CrudServiceTest(String name) |
|
71 |
{ |
|
72 |
super(name); |
|
73 |
} |
|
74 |
|
|
75 |
/** |
|
76 |
* Establish a testing framework by initializing appropriate objects |
|
77 |
*/ |
|
78 |
public void setUp() throws Exception |
|
79 |
{ |
|
80 |
super.setUp(); |
|
81 |
} |
|
82 |
|
|
83 |
/** |
|
84 |
* Release any objects after tests are complete |
|
85 |
*/ |
|
86 |
public void tearDown() |
|
87 |
{ |
|
88 |
System.out.println(createCount + " docs created in this test session."); |
|
89 |
} |
|
90 |
|
|
91 |
/** |
|
92 |
* Create a suite of tests to be run together |
|
93 |
*/ |
|
94 |
public static Test suite() |
|
95 |
{ |
|
96 |
TestSuite suite = new TestSuite(); |
|
97 |
suite.addTest(new CrudServiceTest("initialize")); |
|
98 |
|
|
99 |
suite.addTest(new CrudServiceTest("testSingletonAccessor")); |
|
100 |
suite.addTest(new CrudServiceTest("testCreateAndGet")); |
|
101 |
suite.addTest(new CrudServiceTest("testGetSystemMetadata")); |
|
102 |
suite.addTest(new CrudServiceTest("testUpdate")); |
|
103 |
suite.addTest(new CrudServiceTest("testListObjects")); |
|
104 |
suite.addTest(new CrudServiceTest("testAccessControl")); |
|
105 |
suite.addTest(new CrudServiceTest("testGetLogRecords")); |
|
106 |
suite.addTest(new CrudServiceTest("testChecksumError")); |
|
107 |
suite.addTest(new CrudServiceTest("testPublicAccess")); |
|
108 |
suite.addTest(new CrudServiceTest("testFailedCreate")); |
|
109 |
suite.addTest(new CrudServiceTest("testChecksum")); |
|
110 |
suite.addTest(new CrudServiceTest("testDescribe")); |
|
111 |
suite.addTest(new CrudServiceTest("testDelete")); |
|
112 |
suite.addTest(new CrudServiceTest("testSemiColonsInIdentifiers")); |
|
113 |
return suite; |
|
114 |
} |
|
115 |
|
|
116 |
/** |
|
117 |
* test for the use of semi colons in identifiers |
|
118 |
* in response to https://redmine.dataone.org/issues/1143 |
|
119 |
*/ |
|
120 |
public void testSemiColonsInIdentifiers() |
|
121 |
{ |
|
122 |
try |
|
123 |
{ |
|
124 |
CrudService cs = CrudService.getInstance(); |
|
125 |
AuthToken token = getToken(); |
|
126 |
String testDoc = getTestDoc(); |
|
127 |
|
|
128 |
Identifier id = new Identifier(); |
|
129 |
id.setValue("someid;id;with;semi;colons;in;it." + new Date().getTime()); |
|
130 |
String docid = generateDocumentId(); |
|
131 |
|
|
132 |
//create the system metadata then run the create method |
|
133 |
StringBufferInputStream sbis = new StringBufferInputStream(testDoc); |
|
134 |
SystemMetadata sm = createSystemMetadata(id, testDoc, |
|
135 |
ObjectFormatCache.getInstance().getFormat("eml://ecoinformatics.org/eml-2.1.0")); |
|
136 |
//create the doc |
|
137 |
Identifier rGuid = cs.create(token, id, sbis, sm); |
|
138 |
|
|
139 |
System.out.println("ID: " + rGuid.getValue()); |
|
140 |
assertTrue(rGuid.toString().equals(id.toString())); |
|
141 |
System.out.println("created doc with id " + id.getValue()); |
|
142 |
} |
|
143 |
catch(Exception e) |
|
144 |
{ |
|
145 |
fail("Unexpected error in testDescribe: " + e.getMessage()); |
|
146 |
} |
|
147 |
} |
|
148 |
|
|
149 |
/** |
|
150 |
* test the delete function |
|
151 |
*/ |
|
152 |
public void testDelete() |
|
153 |
{ |
|
154 |
try |
|
155 |
{ |
|
156 |
CrudService cs = CrudService.getInstance(); |
|
157 |
AuthToken token = getToken(); |
|
158 |
String doc = getTestDoc(); |
|
159 |
Identifier id = createDoc(token, doc); |
|
160 |
System.out.println("ID: " + id.getValue()); |
|
161 |
makeDocPublic(token, id, true); |
|
162 |
cs.get(token, id); |
|
163 |
cs.delete(token, id); |
|
164 |
//there should be a try/catch around the next statement |
|
165 |
//to make sure that the document is no longer readable, |
|
166 |
//but because the data is output in a 2nd thread, the |
|
167 |
//exception does not get caught here. See |
|
168 |
//https://redmine.dataone.org/issues/1079 |
|
169 |
//cs.get(token, id); |
|
170 |
} |
|
171 |
catch(Exception e) |
|
172 |
{ |
|
173 |
fail("Unexpected error in testDescribe: " + e.getMessage()); |
|
174 |
} |
|
175 |
} |
|
176 |
|
|
177 |
/** |
|
178 |
* test the describe crud function |
|
179 |
*/ |
|
180 |
public void testDescribe() |
|
181 |
{ |
|
182 |
try |
|
183 |
{ |
|
184 |
CrudService cs = CrudService.getInstance(); |
|
185 |
AuthToken token = getToken(); |
|
186 |
|
|
187 |
String doc = getTestDoc(); |
|
188 |
Identifier id = createDoc(token, doc); |
|
189 |
System.out.println("ID: " + id.getValue()); |
|
190 |
makeDocPublic(token, id, true); |
|
191 |
|
|
192 |
SystemMetadata sm = cs.getSystemMetadata(token, id); |
|
193 |
|
|
194 |
DescribeResponse dr = cs.describe(token, id); |
|
195 |
|
|
196 |
assertTrue(dr.getDataONE_Checksum().getValue().equals(sm.getChecksum().getValue())); |
|
197 |
assertTrue(dr.getDataONE_ObjectFormat().toString().equals(sm.getObjectFormat().getFmtid().getValue())); |
|
198 |
assertTrue(dr.getLast_Modified().getTime() == sm.getDateSysMetadataModified().getTime()); |
|
199 |
assertTrue(dr.getContent_Length() == sm.getSize()); |
|
200 |
} |
|
201 |
catch(Exception e) |
|
202 |
{ |
|
203 |
fail("Unexpected error in testDescribe: " + e.getMessage()); |
|
204 |
} |
|
205 |
} |
|
206 |
|
|
207 |
/** |
|
208 |
* test the checksum creation |
|
209 |
*/ |
|
210 |
public void testChecksum() |
|
211 |
{ |
|
212 |
try |
|
213 |
{ |
|
214 |
CrudService cs = CrudService.getInstance(); |
|
215 |
AuthToken token = getToken(); |
|
216 |
System.out.println("token: " + token.getToken()); |
|
217 |
String doc = getTestDoc(); |
|
218 |
Identifier id = createDoc(token, doc); |
|
219 |
System.out.println("ID: " + id.getValue()); |
|
220 |
makeDocPublic(token, id, true); |
|
221 |
String doc2 = getDoc(token, id); |
|
222 |
|
|
223 |
String checksum = checksum(doc); |
|
224 |
Checksum checksum2 = cs.getChecksum(token, id, "MD5"); |
|
225 |
System.out.println("doc: \"" + doc + "\""); |
|
226 |
System.out.println("doc2: \"" + doc2 + "\""); |
|
227 |
System.out.println("checksum1: " + checksum); |
|
228 |
System.out.println("checksum2: " + checksum2.getValue()); |
|
229 |
assertTrue(checksum.equals(checksum2.getValue())); |
|
230 |
|
|
231 |
} |
|
232 |
catch(Exception e) |
|
233 |
{ |
|
234 |
fail("Unexpected error in testChecksum: " + e.getMessage()); |
|
235 |
} |
|
236 |
|
|
237 |
} |
|
238 |
|
|
239 |
/** |
|
240 |
* insert an invalid document and make sure create fails and does not |
|
241 |
* leave any artifacts behind |
|
242 |
*/ |
|
243 |
public void testFailedCreate() |
|
244 |
{ |
|
245 |
try |
|
246 |
{ |
|
247 |
String invalidDoc = "<xxx></yyy>"; |
|
248 |
System.out.println("trying to insert doc " + invalidDoc); |
|
249 |
CrudService cs = CrudService.getInstance(); |
|
250 |
AuthToken token = getToken(); |
|
251 |
//run create |
|
252 |
try |
|
253 |
{ |
|
254 |
Identifier id = createDoc(token, invalidDoc); |
|
255 |
fail("Should have thrown an exception."); |
|
256 |
} |
|
257 |
catch(Exception e) |
|
258 |
{ |
|
259 |
//e.printStackTrace(); |
|
260 |
} |
|
261 |
|
|
262 |
} |
|
263 |
catch(Exception e) |
|
264 |
{ |
|
265 |
fail("unexpected exception in testFailedCreate: " + e.getMessage()); |
|
266 |
} |
|
267 |
} |
|
268 |
|
|
269 |
/** |
|
270 |
* test to make sure that get and listObjects methods are publicly accessible |
|
271 |
*/ |
|
272 |
public void testPublicAccess() |
|
273 |
{ |
|
274 |
try |
|
275 |
{ |
|
276 |
System.out.println("********************* testPublicAccess *********************"); |
|
277 |
AuthToken token = new AuthToken("public"); |
|
278 |
//AuthToken token = getToken(); |
|
279 |
CrudService cs = CrudService.getInstance(); |
|
280 |
ObjectList ol = cs.listObjects(token, null, null, null); |
|
281 |
System.out.println("ol: " + ol.sizeObjectInfoList()); |
|
282 |
assertTrue(ol.sizeObjectInfoList() > 0); |
|
283 |
|
|
284 |
ObjectInfo oi = ol.getObjectInfo(0); |
|
285 |
String s = getDoc(token, oi.getIdentifier()); |
|
286 |
assertNotNull(s); |
|
287 |
|
|
288 |
try |
|
289 |
{ //try a create with the public auth. should fail |
|
290 |
Identifier id = new Identifier(); |
|
291 |
String docid = generateDocumentId(); |
|
292 |
id.setValue(docid); |
|
293 |
String testDoc = getTestDoc(); |
|
294 |
StringBufferInputStream sbis = new StringBufferInputStream(testDoc); |
|
295 |
ObjectFormat of1 = ObjectFormatCache.getInstance().getFormat("eml://ecoinformatics.org/eml-2.1.0"); |
|
296 |
SystemMetadata sm = createSystemMetadata(id, testDoc, of1); |
|
297 |
assertFalse(sm.getChecksum().getValue().startsWith("MD5")); |
|
298 |
//create the doc |
|
299 |
Identifier idC = cs.create(token, id, sbis, sm); |
|
300 |
fail("Should have thrown an auth exception"); |
|
301 |
} |
|
302 |
catch(Exception e) |
|
303 |
{ |
|
304 |
|
|
305 |
} |
|
306 |
|
|
307 |
//create a legit doc |
|
308 |
token = getToken(); |
|
309 |
Identifier id = new Identifier(); |
|
310 |
String docid = generateDocumentId(); |
|
311 |
id.setValue(docid); |
|
312 |
String testDoc = getTestDoc(); |
|
313 |
StringBufferInputStream sbis = new StringBufferInputStream(testDoc); |
|
314 |
ObjectFormat of1 = ObjectFormatCache.getInstance().getFormat("eml://ecoinformatics.org/eml-2.1.0"); |
|
315 |
SystemMetadata sm = createSystemMetadata(id, testDoc, of1); |
|
316 |
assertFalse(sm.getChecksum().getValue().startsWith("MD5")); |
|
317 |
//create the doc |
|
318 |
Identifier idC = cs.create(token, id, sbis, sm); |
|
319 |
//make it public, then use a public token to try to get it |
|
320 |
InputStream data = null; |
|
321 |
try |
|
322 |
{ |
|
323 |
AuthToken publicToken = new AuthToken("public"); |
|
324 |
data = cs.get(publicToken, id); |
|
325 |
data.read(); |
|
326 |
|
|
327 |
fail("should have thrown an exception"); |
|
328 |
} |
|
329 |
catch(Exception e) |
|
330 |
{ |
|
331 |
/*System.out.println("%%%%%%%%%%%%%%%%%%%%%%%getting result"); |
|
332 |
Object o = ((InputStreamFromOutputStream)data).getResult(); |
|
333 |
System.out.println("result: " + o); |
|
334 |
System.out.println("exception thrown!"); |
|
335 |
System.out.println("exception thrown: " + e.getClass().getName());*/ |
|
336 |
} |
|
337 |
|
|
338 |
|
|
339 |
|
|
340 |
makeDocPublic(token, id, true); |
|
341 |
token = new AuthToken("public"); |
|
342 |
data = cs.get(token, id); |
|
343 |
} |
|
344 |
catch(Exception e) |
|
345 |
{ |
|
346 |
fail("Error in testPublicAccess: " + e.getMessage()); |
|
347 |
} |
|
348 |
|
|
349 |
} |
|
350 |
|
|
351 |
/** |
|
352 |
* test for an error where the checksum algorithm gets appended onto the checksum. |
|
353 |
*/ |
|
354 |
public void testChecksumError() |
|
355 |
{ |
|
356 |
printTestHeader("testChecksumError"); |
|
357 |
try |
|
358 |
{ |
|
359 |
Date d1 = new Date(new Date().getTime() - 5000); |
|
360 |
CrudService cs = CrudService.getInstance(); |
|
361 |
AuthToken token = getToken(); |
|
362 |
ObjectFormat of1 = ObjectFormatCache.getInstance().getFormat("eml://ecoinformatics.org/eml-2.1.0"); |
|
363 |
//create docs at different times |
|
364 |
|
|
365 |
Identifier id = new Identifier(); |
|
366 |
String docid = "test." + new Date().getTime(); |
|
367 |
id.setValue(docid); |
|
368 |
|
|
369 |
//create the system metadata then run the create method |
|
370 |
String testDoc = getTestDoc(); |
|
371 |
StringBufferInputStream sbis = new StringBufferInputStream(testDoc); |
|
372 |
SystemMetadata sm = createSystemMetadata(id, testDoc, of1); |
|
373 |
assertFalse(sm.getChecksum().getValue().startsWith("MD5")); |
|
374 |
//create the doc |
|
375 |
Identifier idC = cs.create(token, id, sbis, sm); |
|
376 |
makeDocPublic(token, id, true); |
|
377 |
assertTrue(idC.getValue().equals(id.getValue())); |
|
378 |
SystemMetadata smC = getSystemMetadata(token, idC); |
|
379 |
assertFalse(smC.getChecksum().getValue().startsWith("MD5")); |
|
380 |
|
|
381 |
Date d2 = new Date(new Date().getTime() + 5000); |
|
382 |
|
|
383 |
ObjectList ol = cs.listObjects(token, d1, d2, of1); |
|
384 |
assertTrue(ol.sizeObjectInfoList() > 0); |
|
385 |
ObjectInfo oi = ol.getObjectInfo(0); |
|
386 |
//this will fail if the error state exists. |
|
387 |
assertFalse(oi.getChecksum().getValue().startsWith("MD5")); |
|
388 |
} |
|
389 |
catch(Exception e) |
|
390 |
{ |
|
391 |
fail("Unexpected exception: " + e.getMessage()); |
|
392 |
} |
|
393 |
|
|
394 |
} |
|
395 |
|
|
396 |
/** |
|
397 |
* test CrudService.getLogRecords |
|
398 |
*/ |
|
399 |
public void testGetLogRecords() |
|
400 |
{ |
|
401 |
printTestHeader("testGetLogRecords"); |
|
402 |
try |
|
403 |
{ |
|
404 |
CrudService cs = CrudService.getInstance(); |
|
405 |
AuthToken token = getToken(); |
|
406 |
Date fromDate = new Date(); |
|
407 |
Identifier id = createDoc(token, getTestDoc()); |
|
408 |
Date toDate = new Date(); |
|
409 |
Log lrs = cs.getLogRecords(token, fromDate, toDate, null); |
|
410 |
assertNotNull(lrs); |
|
411 |
System.out.println("log entry size: " + lrs.sizeLogEntryList()); |
|
412 |
assertTrue(lrs.sizeLogEntryList() == 1); |
|
413 |
LogEntry lrLogEvent = lrs.getLogEntry(0); |
|
414 |
assertTrue(lrLogEvent.getEvent().name().equals("CREATE")); |
|
415 |
assertTrue(lrLogEvent.getIdentifier().getValue().equals(id.getValue())); |
|
416 |
} |
|
417 |
catch(Exception e) |
|
418 |
{ |
|
419 |
e.printStackTrace(); |
|
420 |
fail("testGetLogRecords threw an unexpected exception: " + e.getMessage()); |
|
421 |
} |
|
422 |
} |
|
423 |
|
|
424 |
/** |
|
425 |
* make sure that only valid sessions can update/delete |
|
426 |
*/ |
|
427 |
public void testAccessControl() |
|
428 |
{ |
|
429 |
printTestHeader("testAccessControl"); |
|
430 |
try |
|
431 |
{ |
|
432 |
CrudService cs = CrudService.getInstance(); |
|
433 |
AuthToken token = getToken(); |
|
434 |
//create a doc |
|
435 |
Identifier id = createDoc(token, getTestDoc()); |
|
436 |
|
|
437 |
//get the doc and sysmetadata |
|
438 |
String gotDoc = getDoc(token, id); |
|
439 |
SystemMetadata sm = getSystemMetadata(token, id); |
|
440 |
|
|
441 |
//break the session id |
|
442 |
String sessionid = "somefakesessionid"; |
|
443 |
token = new AuthToken(sessionid); |
|
444 |
|
|
445 |
//update the doc |
|
446 |
gotDoc = gotDoc.replaceAll("XXX", "YYY"); |
|
447 |
Identifier newid = new Identifier(); |
|
448 |
newid.setValue(generateDocumentId()); |
|
449 |
StringBufferInputStream sbis = new StringBufferInputStream(gotDoc); |
|
450 |
SystemMetadata newsm = createSystemMetadata(newid, gotDoc); |
|
451 |
Identifier updatedid = cs.update(token, newid, sbis, id, newsm); |
|
452 |
fail("exception should have been thrown."); |
|
453 |
} |
|
454 |
catch(Exception e) |
|
455 |
{ |
|
456 |
} |
|
457 |
|
|
458 |
try |
|
459 |
{ |
|
460 |
CrudService cs = CrudService.getInstance(); |
|
461 |
AuthToken token = new AuthToken("somefakesessionid"); |
|
462 |
//create a doc |
|
463 |
Identifier id = createDoc(token, getTestDoc()); |
|
464 |
fail("exception should have been thrown."); |
|
465 |
} |
|
466 |
catch(Exception e) |
|
467 |
{ |
|
468 |
} |
|
469 |
} |
|
470 |
|
|
471 |
/** |
|
472 |
* public ObjectList listObjects(AuthToken token, Date startTime, Date endTime, |
|
473 |
* ObjectFormat objectFormat, boolean replicaStatus, int start, int count) |
|
474 |
* throws NotAuthorized, InvalidRequest, NotImplemented, ServiceFailure, InvalidToken |
|
475 |
*/ |
|
476 |
public void testListObjects() |
|
477 |
{ |
|
478 |
printTestHeader("testListObjects"); |
|
479 |
try |
|
480 |
{ |
|
481 |
CrudService cs = CrudService.getInstance(); |
|
482 |
AuthToken token = getToken(); |
|
483 |
ObjectFormat of1 = ObjectFormatCache.getInstance().getFormat("eml://ecoinformatics.org/eml-2.1.0"); |
|
484 |
ObjectFormat of2 = ObjectFormatCache.getInstance().getFormat("eml://ecoinformatics.org/eml-2.0.0"); |
|
485 |
//create docs at different times |
|
486 |
Date d1 = new Date(); |
|
487 |
Identifier id1 = createDoc(token, getTestDoc(EML2_1_0), of1); |
|
488 |
SystemMetadata sm1 = getSystemMetadata(token, id1); |
|
489 |
|
|
490 |
Date d2 = new Date(); |
|
491 |
Identifier id2 = createDoc(token, getTestDoc(EML2_0_0), of2); |
|
492 |
makeDocPublic(token, id2, true); |
|
493 |
SystemMetadata sm2 = getSystemMetadata(token, id2); |
|
494 |
|
|
495 |
Date d3 = new Date(); |
|
496 |
Identifier id3 = createDoc(token, getTestDoc(EML2_1_0), of1); |
|
497 |
makeDocPublic(token, id3, true); |
|
498 |
SystemMetadata sm3 = getSystemMetadata(token, id3); |
|
499 |
|
|
500 |
Date d4 = new Date(); |
|
501 |
Identifier id4 = createDoc(token, getTestDoc(EML2_0_0), of2); |
|
502 |
makeDocPublic(token, id4, true); |
|
503 |
SystemMetadata sm4 = getSystemMetadata(token, id4); |
|
504 |
|
|
505 |
Date d5 = new Date(); |
|
506 |
Identifier id5 = createDoc(token, getTestDoc(EML2_1_0), of1); |
|
507 |
makeDocPublic(token, id5, true); |
|
508 |
SystemMetadata sm5 = getSystemMetadata(token, id5); |
|
509 |
|
|
510 |
Date d6 = new Date(); |
|
511 |
|
|
512 |
//now get the objects for specific time ranges and test that it returns |
|
513 |
//the correct objects |
|
514 |
|
|
515 |
//ObjectList list = cs.listObjects(token, null, null, null); |
|
516 |
//System.out.println("list size: " + list.sizeObjectInfoList()); |
|
517 |
|
|
518 |
//should return sm1 and sm2 |
|
519 |
ObjectList list1 = cs.listObjects(token, d1, d3, null); |
|
520 |
assertTrue(list1.sizeObjectInfoList() == 2); |
|
521 |
assertTrue(idInObjectList(id1, list1)); |
|
522 |
assertTrue(idInObjectList(id2, list1)); |
|
523 |
|
|
524 |
ObjectInfo info = list1.getObjectInfo(0); |
|
525 |
|
|
526 |
|
|
527 |
//should only return sm1 |
|
528 |
ObjectList list2 = cs.listObjects(token, d1, d3, of1); |
|
529 |
assertTrue(list2.sizeObjectInfoList() == 1); |
|
530 |
assertTrue(idInObjectList(id1, list2)); |
|
531 |
|
|
532 |
//should return sm1-sm4 |
|
533 |
ObjectList list3 = cs.listObjects(token, d1, d5, null); |
|
534 |
assertTrue(list3.sizeObjectInfoList() == 4); |
|
535 |
ObjectInfo oi4 = list3.getObjectInfo(0); |
|
536 |
assertTrue(idInObjectList(id1, list3)); |
|
537 |
assertTrue(idInObjectList(id2, list3)); |
|
538 |
assertTrue(idInObjectList(id3, list3)); |
|
539 |
assertTrue(idInObjectList(id4, list3)); |
|
540 |
|
|
541 |
//should only return sm2 and sm4 |
|
542 |
ObjectList list4 = cs.listObjects(token, d1, d5, of2); |
|
543 |
assertTrue(list4.sizeObjectInfoList() == 2); |
|
544 |
assertTrue(idInObjectList(id2, list4)); |
|
545 |
assertTrue(idInObjectList(id4, list4)); |
|
546 |
|
|
547 |
//should return all |
|
548 |
ObjectList list5 = cs.listObjects(token, d1, d6, null); |
|
549 |
assertTrue(list5.sizeObjectInfoList() == 5); |
|
550 |
assertTrue(idInObjectList(id1, list5)); |
|
551 |
assertTrue(idInObjectList(id2, list5)); |
|
552 |
assertTrue(idInObjectList(id3, list5)); |
|
553 |
assertTrue(idInObjectList(id4, list5)); |
|
554 |
assertTrue(idInObjectList(id5, list5)); |
|
555 |
|
|
556 |
//should return 1, 3, 5 |
|
557 |
ObjectList list6 = cs.listObjects(token, d1, d6, of1); |
|
558 |
assertTrue(list6.sizeObjectInfoList() == 3); |
|
559 |
assertTrue(idInObjectList(id1, list6)); |
|
560 |
assertTrue(idInObjectList(id3, list6)); |
|
561 |
assertTrue(idInObjectList(id5, list6)); |
|
562 |
|
|
563 |
//should return 4 (id1 is not public) |
|
564 |
token = new AuthToken("public"); |
|
565 |
ObjectList list7 = cs.listObjects(token, d1, d6, null); |
|
566 |
//System.out.println("list7 size: " + list7.sizeObjectInfoList()); |
|
567 |
assertTrue(list7.sizeObjectInfoList() == 5); |
|
568 |
|
|
569 |
//test paging |
|
570 |
ObjectList list8 = cs.listObjects(token, d1, d6, null, false, 2, 2); |
|
571 |
assertTrue(list8.getCount() == 2); |
|
572 |
assertTrue(list8.getStart() == 2); |
|
573 |
assertTrue(list8.getTotal() == 5); |
|
574 |
|
|
575 |
|
|
576 |
} |
|
577 |
catch(Exception e) |
|
578 |
{ |
|
579 |
//e.printStackTrace(); |
|
580 |
fail("Error in listObjects: " + e.getMessage()); |
|
581 |
} |
|
582 |
} |
|
583 |
|
|
584 |
private boolean idInObjectList(Identifier id, ObjectList list) |
|
585 |
{ |
|
586 |
for(int i=0; i<list.sizeObjectInfoList(); i++) |
|
587 |
{ |
|
588 |
ObjectInfo oi = list.getObjectInfo(i); |
|
589 |
if(id.getValue().equals(oi.getIdentifier().getValue())) |
|
590 |
return true; |
|
591 |
} |
|
592 |
return false; |
|
593 |
} |
|
594 |
|
|
595 |
/** |
|
596 |
* public Identifier update(AuthToken token, Identifier guid, |
|
597 |
* InputStream object, Identifier obsoletedGuid, SystemMetadata sysmeta) |
|
598 |
* throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique, |
|
599 |
* UnsupportedType, InsufficientResources, NotFound, InvalidSystemMetadata, |
|
600 |
* NotImplemented |
|
601 |
*/ |
|
602 |
public void testUpdate() |
|
603 |
{ |
|
604 |
printTestHeader("testUpdate"); |
|
605 |
try |
|
606 |
{ |
|
607 |
CrudService cs = CrudService.getInstance(); |
|
608 |
AuthToken token = getToken(); |
|
609 |
//create a doc |
|
610 |
Identifier id = createDoc(token, getTestDoc()); |
|
611 |
|
|
612 |
//get the doc and sysmetadata |
|
613 |
String gotDoc = getDoc(token, id); |
|
614 |
SystemMetadata sm = getSystemMetadata(token, id); |
|
615 |
|
|
616 |
//update the doc |
|
617 |
gotDoc = gotDoc.replaceAll("XXX", "YYY"); |
|
618 |
Identifier newid = new Identifier(); |
|
619 |
newid.setValue(generateDocumentId()); |
|
620 |
StringBufferInputStream sbis = new StringBufferInputStream(gotDoc); |
|
621 |
SystemMetadata newsm = createSystemMetadata(newid, gotDoc); |
|
622 |
Identifier updatedid = cs.update(token, newid, sbis, id, newsm); |
|
623 |
|
|
624 |
//get doc - check that it matches update |
|
625 |
String newdoc = getDoc(token, newid); |
|
626 |
assertTrue(gotDoc.equals(newdoc)); |
|
627 |
|
|
628 |
//get sysmeta - check that ids and other fields are updated |
|
629 |
SystemMetadata newnewsm = getSystemMetadata(token, id); |
|
630 |
assertTrue(newnewsm.getObsoletedBy(0).getValue().equals(newid.getValue())); |
|
631 |
|
|
632 |
//get the new sysmeta and make sure the obsoletes field is set |
|
633 |
SystemMetadata newnewnewsm = getSystemMetadata(token, newid); |
|
634 |
assertTrue(newnewnewsm.getObsolete(0).getValue().equals(id.getValue())); |
|
635 |
} |
|
636 |
catch(Exception e) |
|
637 |
{ |
|
638 |
e.printStackTrace(); |
|
639 |
fail("Error in testUpdate: " + e.getMessage()); |
|
640 |
} |
|
641 |
} |
|
642 |
|
|
643 |
/** |
|
644 |
* public SystemMetadata getSystemMetadata(AuthToken token, Identifier guid) |
|
645 |
* throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, |
|
646 |
* InvalidRequest, NotImplemented |
|
647 |
*/ |
|
648 |
public void testGetSystemMetadata() |
|
649 |
{ |
|
650 |
printTestHeader("testGetSystemMetadata"); |
|
651 |
try |
|
652 |
{ |
|
653 |
CrudService cs = CrudService.getInstance(); |
|
654 |
AuthToken token = getToken(); |
|
655 |
//run create |
|
656 |
Identifier id = createDoc(token, getTestDoc()); |
|
657 |
//get the systemMetadata and make sure it is the correct object for this testDoc |
|
658 |
SystemMetadata sm = getSystemMetadata(token, id); |
|
659 |
assertTrue(sm.getIdentifier().getValue().equals(id.getValue())); |
|
660 |
assertTrue(sm.getChecksum().getValue().equals(checksum(getTestDoc()))); |
|
661 |
|
|
662 |
try |
|
663 |
{ |
|
664 |
Identifier fakeid = new Identifier(); |
|
665 |
fakeid.setValue("somethingfake.234234"); |
|
666 |
getSystemMetadata(token, fakeid); |
|
667 |
fail("getSystemMetadata should have thrown an exception."); |
|
668 |
} |
|
669 |
catch(Exception e) |
|
670 |
{ |
|
671 |
assertTrue(true); |
|
672 |
} |
|
673 |
} |
|
674 |
catch(Exception e) |
|
675 |
{ |
|
676 |
e.printStackTrace(); |
|
677 |
fail("Error testing system metadata: " + e.getMessage()); |
|
678 |
} |
|
679 |
} |
|
680 |
|
|
681 |
/** |
|
682 |
* create(AuthToken token, Identifier guid, InputStream object, SystemMetadata sysmeta) |
|
683 |
* throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique, UnsupportedType, |
|
684 |
* InsufficientResources, InvalidSystemMetadata, NotImplemented |
|
685 |
* |
|
686 |
* public InputStream get(AuthToken token, Identifier guid) |
|
687 |
* throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, |
|
688 |
* NotImplemented |
|
689 |
*/ |
|
690 |
public void testCreateAndGet() |
|
691 |
{ |
|
692 |
printTestHeader("testCreateAndGet"); |
|
693 |
try |
|
694 |
{ |
|
695 |
CrudService cs = CrudService.getInstance(); |
|
696 |
AuthToken token = getToken(); |
|
697 |
//run create |
|
698 |
Identifier id = createDoc(token, getTestDoc()); |
|
699 |
//make these docs public for debugging purposes. |
|
700 |
makeDocPublic(token, id, true); |
|
701 |
//compare the docs |
|
702 |
String gotDoc = getDoc(token, id); |
|
703 |
assertTrue(gotDoc.trim().equals(getTestDoc().trim())); |
|
704 |
|
|
705 |
try |
|
706 |
{ |
|
707 |
Identifier fakeid = new Identifier(); |
|
708 |
fakeid.setValue("somethingfake.234234"); |
|
709 |
getDoc(token, fakeid); |
|
710 |
fail("testCreateAndGet should have thrown an exception."); |
|
711 |
} |
|
712 |
catch(Exception e) |
|
713 |
{ |
|
714 |
assertTrue(true); |
|
715 |
} |
|
716 |
} |
|
717 |
catch(Exception e) |
|
718 |
{ |
|
719 |
e.printStackTrace(); |
|
720 |
fail("Error in testCreate: " + e.getMessage()); |
|
721 |
} |
|
722 |
} |
|
723 |
|
|
724 |
/** |
|
725 |
* getInstance() |
|
726 |
*/ |
|
727 |
public void testSingletonAccessor() |
|
728 |
{ |
|
729 |
printTestHeader("testSingletonAccessor"); |
|
730 |
CrudService cs = CrudService.getInstance(); |
|
731 |
assertNotNull(cs); |
|
732 |
} |
|
733 |
|
|
734 |
/** |
|
735 |
* Run an initial test that always passes to check that the test harness is |
|
736 |
* working. |
|
737 |
*/ |
|
738 |
public void initialize() |
|
739 |
{ |
|
740 |
printTestHeader("initialize"); |
|
741 |
assertTrue(1 == 1); |
|
742 |
} |
|
743 |
|
|
744 |
/** |
|
745 |
* return the systemMetadata object for id |
|
746 |
*/ |
|
747 |
private SystemMetadata getSystemMetadata(AuthToken token, Identifier id) |
|
748 |
throws BaseException |
|
749 |
{ |
|
750 |
CrudService cs = CrudService.getInstance(); |
|
751 |
return cs.getSystemMetadata(token, id); |
|
752 |
} |
|
753 |
|
|
754 |
/** |
|
755 |
* get a doc from metacat using CrudService.get() |
|
756 |
*/ |
|
757 |
private String getDoc(AuthToken token, Identifier id) |
|
758 |
throws Exception |
|
759 |
{ |
|
760 |
CrudService cs = CrudService.getInstance(); |
|
761 |
InputStream gotDocStream = cs.get(token, id); |
|
762 |
return IOUtils.toString(gotDocStream); |
|
763 |
} |
|
764 |
|
|
765 |
public String getTestDoc() |
|
766 |
{ |
|
767 |
return getTestDoc("eml://ecoinformatics.org/eml-2.1.0"); |
|
768 |
} |
|
769 |
|
|
770 |
/** |
|
771 |
* return a test document. objectFormat should come from MCTestCase |
|
772 |
*/ |
|
773 |
public String getTestDoc(String objectFormat) |
|
774 |
{ |
|
775 |
if(objectFormat == null) |
|
776 |
{ |
|
777 |
return "<?xml version=\"1.0\"?><test><somecontent>This is some content XXX</somecontent></test>\n"; |
|
778 |
} |
|
779 |
|
|
780 |
String accessBlock = getAccessBlock("public", true, true, |
|
781 |
false, false, false); |
|
782 |
|
|
783 |
|
|
784 |
return getTestEmlDoc("Test identifier manager", objectFormat, null, |
|
785 |
null, "http://fake.example.com/somedata", null, |
|
786 |
accessBlock, null, null, |
|
787 |
null, null); |
|
788 |
} |
|
789 |
|
|
790 |
/** |
|
791 |
* authenticate and return a token |
|
792 |
* use the test.mcUser and test.mcPassword username/password combo |
|
793 |
*/ |
|
794 |
public AuthToken getToken() |
|
795 |
throws Exception |
|
796 |
{ |
|
797 |
String username = PropertyService.getProperty("test.mcUser"); |
|
798 |
String password = PropertyService.getProperty("test.mcPassword"); |
|
799 |
return getToken(username, password); |
|
800 |
} |
|
801 |
|
|
802 |
/** |
|
803 |
* authenticate and return a token using the given credentials |
|
804 |
*/ |
|
805 |
public AuthToken getToken(String username, String password) |
|
806 |
throws Exception |
|
807 |
{ |
|
808 |
CrudService cs = CrudService.getInstance(); |
|
809 |
//login and get a sessionid |
|
810 |
MetacatRestClient restClient = new MetacatRestClient(cs.getContextUrl()); |
|
811 |
String response = restClient.login(username, password); |
|
812 |
String sessionid = restClient.getSessionId(); |
|
813 |
SessionService sessionService = SessionService.getInstance(); |
|
814 |
sessionService.registerSession(new SessionData(sessionid, username, new String[0], password, "CrudServiceLogin")); |
|
815 |
AuthToken token = new AuthToken(sessionid); |
|
816 |
return token; |
|
817 |
} |
|
818 |
|
|
819 |
/** |
|
820 |
* create a doc using CrudService.create() and return its id |
|
821 |
*/ |
|
822 |
public Identifier createDoc(AuthToken token, String testDoc) throws Exception |
|
823 |
{ |
|
824 |
return createDoc(token, testDoc, ObjectFormatCache.getInstance().getFormat("eml://ecoinformatics.org/eml-2.1.0")); |
|
825 |
} |
|
826 |
|
|
827 |
/** |
|
828 |
* create a doc using CrudService.create() and return its id |
|
829 |
*/ |
|
830 |
public Identifier createDoc(AuthToken token, String testDoc, ObjectFormat format) throws Exception |
|
831 |
{ |
|
832 |
Identifier id; |
|
833 |
CrudService cs = CrudService.getInstance(); |
|
834 |
|
|
835 |
id = new Identifier(); |
|
836 |
String docid = generateDocumentId(); |
|
837 |
id.setValue(docid); |
|
838 |
|
|
839 |
//create the system metadata then run the create method |
|
840 |
StringBufferInputStream sbis = new StringBufferInputStream(testDoc); |
|
841 |
SystemMetadata sm = createSystemMetadata(id, testDoc, format); |
|
842 |
//create the doc |
|
843 |
cs.create(token, id, sbis, sm); |
|
844 |
createCount++; |
|
845 |
return id; |
|
846 |
} |
|
847 |
|
|
848 |
/** |
|
849 |
* create a generic SystemMetadata object for testing |
|
850 |
*/ |
|
851 |
private SystemMetadata createSystemMetadata(Identifier id, String testDoc) |
|
852 |
throws Exception |
|
853 |
{ |
|
854 |
return createSystemMetadata(id, testDoc, |
|
855 |
ObjectFormatCache.getInstance().getFormat("eml://ecoinformatics.org/eml-2.1.0")); |
|
856 |
} |
|
857 |
|
|
858 |
/** |
|
859 |
* create system metadata with a specified id, doc and format |
|
860 |
*/ |
|
861 |
private SystemMetadata createSystemMetadata(Identifier id, String testDoc, ObjectFormat format) |
|
862 |
throws Exception |
|
863 |
{ |
|
864 |
SystemMetadata sm = new SystemMetadata(); |
|
865 |
//set the id |
|
866 |
sm.setIdentifier(id); |
|
867 |
sm.setObjectFormat(format); |
|
868 |
//create the checksum |
|
869 |
String checksumS = checksum(testDoc); |
|
870 |
ChecksumAlgorithm ca = ChecksumAlgorithm.convert("MD5"); |
|
871 |
Checksum checksum = new Checksum(); |
|
872 |
checksum.setValue(checksumS); |
|
873 |
checksum.setAlgorithm(ca); |
|
874 |
sm.setChecksum(checksum); |
|
875 |
//set the size |
|
876 |
sm.setSize(testDoc.getBytes(MetaCatServlet.DEFAULT_ENCODING).length); |
|
877 |
//submitter |
|
878 |
Subject p = new Subject(); |
|
879 |
p.setValue("joe"); |
|
880 |
sm.setSubmitter(p); |
|
881 |
sm.setRightsHolder(p); |
|
882 |
sm.setDateUploaded(new Date()); |
|
883 |
sm.setDateSysMetadataModified(new Date()); |
|
884 |
NodeReference nr = new NodeReference(); |
|
885 |
nr.setValue("metacat"); |
|
886 |
sm.setOriginMemberNode(nr); |
|
887 |
sm.setAuthoritativeMemberNode(nr); |
|
888 |
return sm; |
|
889 |
} |
|
890 |
|
|
891 |
/** |
|
892 |
* make a document public in metacat by inserting an access document |
|
893 |
* @param id |
|
894 |
*/ |
|
895 |
private void makeDocPublic(AuthToken token, Identifier id, boolean systemMetadataToo) |
|
896 |
throws Exception |
|
897 |
{ |
|
898 |
CrudService cs = CrudService.getInstance(); |
|
899 |
cs.setAccess(token, id, "public", "read", "allow", "allowFirst", systemMetadataToo); |
|
900 |
} |
|
901 |
|
|
902 |
/** |
|
903 |
* print a header to start each test |
|
904 |
*/ |
|
905 |
private void printTestHeader(String testName) |
|
906 |
{ |
|
907 |
System.out.println(); |
|
908 |
System.out.println("*************** " + testName + " ***************"); |
|
909 |
} |
|
910 |
|
|
911 |
/** |
|
912 |
* produce an md5 checksum for item |
|
913 |
*/ |
|
914 |
private String checksum(String item) |
|
915 |
throws Exception |
|
916 |
{ |
|
917 |
StringBufferInputStream fis = new StringBufferInputStream(item); |
|
918 |
|
|
919 |
byte[] buffer = new byte[1024]; |
|
920 |
MessageDigest complete = MessageDigest.getInstance("MD5"); |
|
921 |
int numRead; |
|
922 |
|
|
923 |
do |
|
924 |
{ |
|
925 |
numRead = fis.read(buffer); |
|
926 |
if (numRead > 0) |
|
927 |
{ |
|
928 |
complete.update(buffer, 0, numRead); |
|
929 |
} |
|
930 |
} while (numRead != -1); |
|
931 |
|
|
932 |
|
|
933 |
return getHex(complete.digest()); |
|
934 |
} |
|
935 |
|
|
936 |
/** |
|
937 |
* convert a byte array to a hex string |
|
938 |
*/ |
|
939 |
private static String getHex( byte [] raw ) |
|
940 |
{ |
|
941 |
final String HEXES = "0123456789ABCDEF"; |
|
942 |
if ( raw == null ) { |
|
943 |
return null; |
|
944 |
} |
|
945 |
final StringBuilder hex = new StringBuilder( 2 * raw.length ); |
|
946 |
for ( final byte b : raw ) { |
|
947 |
hex.append(HEXES.charAt((b & 0xF0) >> 4)) |
|
948 |
.append(HEXES.charAt((b & 0x0F))); |
|
949 |
} |
|
950 |
return hex.toString(); |
|
951 |
} |
|
952 |
} |
src/edu/ucsb/nceas/metacat/dataone/CrudService.java | ||
---|---|---|
1 |
/** |
|
2 |
* '$RCSfile$' |
|
3 |
* Copyright: 2000 Regents of the University of California and the |
|
4 |
* National Center for Ecological Analysis and Synthesis |
|
5 |
* |
|
6 |
* '$Author: $' |
|
7 |
* '$Date: 2009-06-13 15:28:13 +0300 $' |
|
8 |
* |
|
9 |
* This program is free software; you can redistribute it and/or modify |
|
10 |
* it under the terms of the GNU General Public License as published by |
|
11 |
* the Free Software Foundation; either version 2 of the License, or |
|
12 |
* (at your option) any later version. |
|
13 |
* |
|
14 |
* This program is distributed in the hope that it will be useful, |
|
15 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
16 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
17 |
* GNU General Public License for more details. |
|
18 |
* |
|
19 |
* You should have received a copy of the GNU General Public License |
|
20 |
* along with this program; if not, write to the Free Software |
|
21 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
22 |
*/ |
|
23 |
package edu.ucsb.nceas.metacat.dataone; |
|
24 |
|
|
25 |
import java.io.ByteArrayInputStream; |
|
26 |
import java.io.File; |
|
27 |
import java.io.FileInputStream; |
|
28 |
import java.io.FileNotFoundException; |
|
29 |
import java.io.FileOutputStream; |
|
30 |
import java.io.IOException; |
|
31 |
import java.io.InputStream; |
|
32 |
import java.io.OutputStream; |
|
33 |
import java.security.NoSuchAlgorithmException; |
|
34 |
import java.sql.SQLException; |
|
35 |
import java.text.DateFormat; |
|
36 |
import java.util.Calendar; |
|
37 |
import java.util.Date; |
|
38 |
import java.util.Enumeration; |
|
39 |
import java.util.Hashtable; |
|
40 |
import java.util.List; |
|
41 |
import java.util.TimeZone; |
|
42 |
import java.util.Timer; |
|
43 |
import java.util.TimerTask; |
|
44 |
import java.util.Vector; |
|
45 |
|
|
46 |
import javax.servlet.http.HttpServletRequest; |
|
47 |
|
|
48 |
import org.apache.commons.io.IOUtils; |
|
49 |
import org.apache.log4j.Logger; |
|
50 |
import org.dataone.service.exceptions.IdentifierNotUnique; |
|
51 |
import org.dataone.service.exceptions.InsufficientResources; |
|
52 |
import org.dataone.service.exceptions.InvalidRequest; |
|
53 |
import org.dataone.service.exceptions.InvalidSystemMetadata; |
|
54 |
import org.dataone.service.exceptions.InvalidToken; |
|
55 |
import org.dataone.service.exceptions.NotAuthorized; |
|
56 |
import org.dataone.service.exceptions.NotFound; |
|
57 |
import org.dataone.service.exceptions.NotImplemented; |
|
58 |
import org.dataone.service.exceptions.ServiceFailure; |
|
59 |
import org.dataone.service.exceptions.UnsupportedType; |
|
60 |
import org.dataone.service.mn.MemberNodeCrud; |
|
61 |
import org.dataone.service.types.AuthToken; |
|
62 |
import org.dataone.service.types.Checksum; |
|
63 |
import org.dataone.service.types.ChecksumAlgorithm; |
|
64 |
import org.dataone.service.types.DescribeResponse; |
|
65 |
import org.dataone.service.types.Event; |
|
66 |
import org.dataone.service.types.Identifier; |
|
67 |
import org.dataone.service.types.Log; |
|
68 |
import org.dataone.service.types.LogEntry; |
|
69 |
import org.dataone.service.types.NodeReference; |
|
70 |
import org.dataone.service.types.ObjectFormat; |
|
71 |
import org.dataone.service.types.ObjectList; |
|
72 |
import org.dataone.service.types.Subject; |
|
73 |
import org.dataone.service.types.SystemMetadata; |
|
74 |
import org.dataone.service.types.util.ServiceTypeUtil; |
|
75 |
|
|
76 |
import edu.ucsb.nceas.metacat.AccessionNumberException; |
|
77 |
import edu.ucsb.nceas.metacat.DocumentImpl; |
|
78 |
import edu.ucsb.nceas.metacat.EventLog; |
|
79 |
import edu.ucsb.nceas.metacat.IdentifierManager; |
|
80 |
import edu.ucsb.nceas.metacat.McdbDocNotFoundException; |
|
81 |
import edu.ucsb.nceas.metacat.McdbException; |
|
82 |
import edu.ucsb.nceas.metacat.MetacatHandler; |
|
83 |
import edu.ucsb.nceas.metacat.client.InsufficientKarmaException; |
|
84 |
import edu.ucsb.nceas.metacat.client.rest.MetacatRestClient; |
|
85 |
import edu.ucsb.nceas.metacat.properties.PropertyService; |
|
86 |
import edu.ucsb.nceas.metacat.replication.ForceReplicationHandler; |
|
87 |
import edu.ucsb.nceas.metacat.service.SessionService; |
|
88 |
import edu.ucsb.nceas.metacat.util.DocumentUtil; |
|
89 |
import edu.ucsb.nceas.metacat.util.SessionData; |
|
90 |
import edu.ucsb.nceas.utilities.ParseLSIDException; |
|
91 |
import edu.ucsb.nceas.utilities.PropertyNotFoundException; |
|
92 |
|
|
93 |
/** |
|
94 |
* |
|
95 |
* Implements DataONE MemberNode CRUD API for Metacat. |
|
96 |
* |
|
97 |
* @author Matthew Jones |
|
98 |
*/ |
|
99 |
public class CrudService implements MemberNodeCrud |
|
100 |
{ |
|
101 |
private static CrudService crudService = null; |
|
102 |
|
|
103 |
private MetacatHandler handler; |
|
104 |
private Hashtable<String, String[]> params; |
|
105 |
private Logger logMetacat = null; |
|
106 |
private Logger logCrud = null; |
|
107 |
|
|
108 |
private String metacatUrl; |
|
109 |
|
|
110 |
/** |
|
111 |
* singleton accessor |
|
112 |
*/ |
|
113 |
public static CrudService getInstance() |
|
114 |
{ |
|
115 |
if(crudService == null) |
|
116 |
{ |
|
117 |
crudService = new CrudService(); |
|
118 |
} |
|
119 |
|
|
120 |
return crudService; |
|
121 |
} |
|
122 |
|
|
123 |
/** |
|
124 |
* Constructor, private for singleton access |
|
125 |
*/ |
|
126 |
private CrudService() { |
|
127 |
logMetacat = Logger.getLogger(CrudService.class); |
|
128 |
logCrud = Logger.getLogger("DataOneLogger"); |
|
129 |
try |
|
130 |
{ |
|
131 |
String server = PropertyService.getProperty("server.name"); |
|
132 |
String port = PropertyService.getProperty("server.httpPort"); |
|
133 |
String context = PropertyService.getProperty("application.context"); |
|
134 |
metacatUrl = "http://" + server + ":" + port + "/" + context + "/d1"; |
|
135 |
logMetacat.debug("Initializing CrudService with url " + metacatUrl); |
|
136 |
} |
|
137 |
catch(Exception e) |
|
138 |
{ |
|
139 |
logMetacat.error("Could not find servlet url in CrudService: " + e.getMessage()); |
|
140 |
e.printStackTrace(); |
|
141 |
throw new RuntimeException("Error getting servlet url in CrudService: " + e.getMessage()); |
|
142 |
} |
|
143 |
|
|
144 |
params = new Hashtable<String, String[]>(); |
|
145 |
handler = new MetacatHandler(new Timer()); |
|
146 |
} |
|
147 |
|
|
148 |
/** |
|
149 |
* return the context url CrudService is using. |
|
150 |
*/ |
|
151 |
public String getContextUrl() |
|
152 |
{ |
|
153 |
return metacatUrl; |
|
154 |
} |
|
155 |
|
|
156 |
/** |
|
157 |
* Set the context url that this service uses. It is normally not necessary |
|
158 |
* to call this method unless you are trying to connect to a server other |
|
159 |
* than the one in which this service is installed. Otherwise, this value is |
|
160 |
* taken from the metacat.properties file (server.name, server.port, application.context). |
|
161 |
*/ |
|
162 |
public void setContextUrl(String url) |
|
163 |
{ |
|
164 |
metacatUrl = url; |
|
165 |
} |
|
166 |
|
|
167 |
/** |
|
168 |
* set the params for this service from an HttpServletRequest param list |
|
169 |
*/ |
|
170 |
public void setParamsFromRequest(HttpServletRequest request) |
|
171 |
{ |
|
172 |
@SuppressWarnings("unchecked") |
|
173 |
Enumeration<String> paramlist = request.getParameterNames(); |
|
174 |
while (paramlist.hasMoreElements()) { |
|
175 |
String name = (String) paramlist.nextElement(); |
|
176 |
String[] value = (String[])request.getParameterValues(name); |
|
177 |
params.put(name, value); |
|
178 |
} |
|
179 |
} |
|
180 |
|
|
181 |
/** |
|
182 |
* Authenticate against metacat and get a token. |
|
183 |
* @param username |
|
184 |
* @param password |
|
185 |
* @return |
|
186 |
* @throws ServiceFailure |
|
187 |
*/ |
|
188 |
public AuthToken authenticate(String username, String password) |
|
189 |
throws ServiceFailure |
|
190 |
{ |
|
191 |
/* TODO: |
|
192 |
* This method is not in the original D1 crud spec. It is highly |
|
193 |
* metacat centric. Higher level decisions need to be made on authentication |
|
194 |
* interfaces for D1 nodes. |
|
195 |
*/ |
|
196 |
try |
|
197 |
{ |
|
198 |
MetacatRestClient restClient = new MetacatRestClient(getContextUrl()); |
|
199 |
String response = restClient.login(username, password); |
|
200 |
String sessionid = restClient.getSessionId(); |
|
201 |
SessionService sessionService = SessionService.getInstance(); |
|
202 |
sessionService.registerSession(new SessionData(sessionid, username, new String[0], password, "CrudServiceLogin")); |
|
203 |
AuthToken token = new AuthToken(sessionid); |
|
204 |
EventLog.getInstance().log(metacatUrl, |
|
205 |
username, null, "authenticate"); |
|
206 |
logCrud.info("authenticate"); |
|
207 |
return token; |
|
208 |
} |
|
209 |
catch(Exception e) |
|
210 |
{ |
|
211 |
throw new ServiceFailure("1620", "Error authenticating with metacat: " + e.getMessage()); |
|
212 |
} |
|
213 |
} |
|
214 |
|
|
215 |
/** |
|
216 |
* set the parameter values needed for this request |
|
217 |
*/ |
|
218 |
public void setParameter(String name, String[] value) |
|
219 |
{ |
|
220 |
params.put(name, value); |
|
221 |
} |
|
222 |
|
|
223 |
|
|
224 |
|
|
225 |
|
|
226 |
|
|
227 |
/** |
|
228 |
* create an object via the crud interface |
|
229 |
*/ |
|
230 |
public Identifier create(AuthToken token, Identifier guid, |
|
231 |
InputStream object, SystemMetadata sysmeta) throws InvalidToken, |
|
232 |
ServiceFailure, NotAuthorized, IdentifierNotUnique, UnsupportedType, |
|
233 |
InsufficientResources, InvalidSystemMetadata, NotImplemented { |
|
234 |
logMetacat.debug("Starting CrudService.create()..."); |
|
235 |
|
|
236 |
// authenticate & get user info |
|
237 |
SessionData sessionData = getSessionData(token); |
|
238 |
String username = "public"; |
|
239 |
String[] groups = null; |
|
240 |
if(sessionData != null) |
|
241 |
{ |
|
242 |
username = sessionData.getUserName(); |
|
243 |
groups = sessionData.getGroupNames(); |
|
244 |
} |
|
245 |
String localId = null; |
|
246 |
|
|
247 |
if (username == null || username.equals("public")) |
|
248 |
{ |
|
249 |
//TODO: many of the thrown exceptions do not use the correct error codes |
|
250 |
//check these against the docs and correct them |
|
251 |
throw new NotAuthorized("1100", "User " + username + " is not authorized to create content." + |
|
252 |
" If you are not logged in, please do so and retry the request."); |
|
253 |
} |
|
254 |
|
|
255 |
// verify that guid == SystemMetadata.getIdentifier() |
|
256 |
logMetacat.debug("Comparing guid|sysmeta_guid: " + guid.getValue() + "|" + sysmeta.getIdentifier().getValue()); |
|
257 |
if (!guid.getValue().equals(sysmeta.getIdentifier().getValue())) { |
|
258 |
throw new InvalidSystemMetadata("1180", |
|
259 |
"GUID in method call (" + guid.getValue() + ") does not match GUID in system metadata (" + |
|
260 |
sysmeta.getIdentifier().getValue() + ")."); |
|
261 |
} |
|
262 |
|
|
263 |
logMetacat.debug("Checking if identifier exists..."); |
|
264 |
// Check that the identifier does not already exist |
|
265 |
IdentifierManager im = IdentifierManager.getInstance(); |
|
266 |
if (im.identifierExists(guid.getValue())) { |
|
267 |
throw new IdentifierNotUnique("1120", |
|
268 |
"GUID is already in use by an existing object."); |
|
269 |
} |
|
270 |
|
|
271 |
// Check if we are handling metadata or data |
|
272 |
boolean isScienceMetadata = isScienceMetadata(sysmeta); |
|
273 |
|
|
274 |
if (isScienceMetadata) { |
|
275 |
// CASE METADATA: |
|
276 |
try { |
|
277 |
//logCrud.debug("CrudService: inserting document with guid " + guid.getValue()); |
|
278 |
this.insertDocument(object, guid, sessionData); |
|
279 |
localId = im.getLocalId(guid.getValue()); |
|
280 |
} catch (IOException e) { |
|
281 |
String msg = "Could not create string from XML stream: " + |
|
282 |
" " + e.getMessage(); |
|
283 |
logMetacat.debug(msg); |
|
284 |
throw new ServiceFailure("1190", msg); |
|
285 |
} catch(Exception e) { |
|
286 |
String msg = "Unexpected error in CrudService.create: " + e.getMessage(); |
|
287 |
logMetacat.debug(msg); |
|
288 |
throw new ServiceFailure("1190", msg); |
|
289 |
} |
|
290 |
|
|
291 |
|
|
292 |
} else { |
|
293 |
// DEFAULT CASE: DATA (needs to be checked and completed) |
|
294 |
localId = insertDataObject(object, guid, sessionData); |
|
295 |
|
|
296 |
} |
|
297 |
|
|
298 |
// For Metadata and Data, insert the system metadata into the object store too |
|
299 |
insertSystemMetadata(sysmeta, sessionData); |
|
300 |
//get the document info. add any access params for the sysmeta too |
|
301 |
//logCrud.debug("looking for access records to add for system " + |
|
302 |
// "metadata who's parent doc's local id is " + localId); |
|
303 |
try |
|
304 |
{ |
|
305 |
Hashtable<String, Object> h = im.getDocumentInfo(localId.substring(0, localId.lastIndexOf("."))); |
|
306 |
Vector v = (Vector)h.get("access"); |
|
307 |
for(int i=0; i<v.size(); i++) |
|
308 |
{ |
|
309 |
@SuppressWarnings("unchecked") |
|
310 |
Hashtable<String, String> ah = (Hashtable<String, String>)v.elementAt(i); |
|
311 |
String principal = (String)ah.get("principal_name"); |
|
312 |
String permission = (String)ah.get("permission"); |
|
313 |
String permissionType = (String)ah.get("permission_type"); |
|
314 |
String permissionOrder = (String)ah.get("permission_order"); |
|
315 |
int perm = new Integer(permission).intValue(); |
|
316 |
//logCrud.debug("found access record for principal " + principal); |
|
317 |
//logCrud.debug("permission: " + perm + " perm_type: " + permissionType + |
|
318 |
// " perm_order: " + permissionOrder); |
|
319 |
this.setAccess(token, guid, principal, perm, permissionType, permissionOrder, true); |
|
320 |
} |
|
321 |
} |
|
322 |
catch(Exception e) |
|
323 |
{ |
|
324 |
logMetacat.error("Error setting permissions on System Metadata object: " + |
|
325 |
e.getMessage()); |
|
326 |
//TODO: decide if this error should cancel the entire create or |
|
327 |
//if it should continue with just a logged error. |
|
328 |
} |
|
329 |
|
|
330 |
|
|
331 |
logMetacat.debug("Returning from CrudService.create()"); |
|
332 |
EventLog.getInstance().log(metacatUrl, |
|
333 |
username, localId, "create"); |
|
334 |
logCrud.info("create D1GUID:" + guid.getValue() + ":D1SCIMETADATA:" + localId); |
|
335 |
return guid; |
|
336 |
} |
|
337 |
|
|
338 |
/** |
|
339 |
* update an existing object with a new object. Change the system metadata |
|
340 |
* to reflect the changes and update it as well. |
|
341 |
*/ |
|
342 |
public Identifier update(AuthToken token, Identifier guid, |
|
343 |
InputStream object, Identifier obsoletedGuid, SystemMetadata sysmeta) |
|
344 |
throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique, |
|
345 |
UnsupportedType, InsufficientResources, NotFound, InvalidSystemMetadata, |
|
346 |
NotImplemented { |
|
347 |
try |
|
348 |
{ |
|
349 |
SessionData sessionData = getSessionData(token); |
|
350 |
|
|
351 |
//find the old systemmetadata (sm.old) document id (the one linked to obsoletedGuid) |
|
352 |
SystemMetadata sm = getSystemMetadata(token, obsoletedGuid); |
|
353 |
//change sm.old's obsoletedBy field |
|
354 |
List<Identifier> l = sm.getObsoletedByList(); |
|
355 |
l.add(guid); |
|
356 |
sm.setObsoletedByList(l); |
|
357 |
//update sm.old |
|
358 |
updateSystemMetadata(sm, sessionData); |
|
359 |
|
|
360 |
//change the obsoletes field of the new systemMetadata (sm.new) to point to the id of the old one |
|
361 |
sysmeta.addObsolete(obsoletedGuid); |
|
362 |
//insert sm.new |
|
363 |
insertSystemMetadata(sysmeta, sessionData); |
|
364 |
String localId; |
|
365 |
|
|
366 |
boolean isScienceMetadata = isScienceMetadata(sysmeta); |
|
367 |
if(isScienceMetadata) |
|
368 |
{ |
|
369 |
//update the doc |
|
370 |
localId = updateDocument(object, obsoletedGuid, guid, sessionData, false); |
|
371 |
} |
|
372 |
else |
|
373 |
{ |
|
374 |
//update a data file, not xml |
|
375 |
localId = insertDataObject(object, guid, sessionData); |
|
376 |
} |
|
377 |
|
|
378 |
IdentifierManager im = IdentifierManager.getInstance(); |
|
379 |
String username = "public"; |
|
380 |
if(sessionData != null) |
|
381 |
{ |
|
382 |
username = sessionData.getUserName(); |
|
383 |
} |
|
384 |
EventLog.getInstance().log(metacatUrl, |
|
385 |
username, im.getLocalId(guid.getValue()), "update"); |
|
386 |
logCrud.info("update D1GUID:" + guid.getValue() + ":D1SCIMETADATA:" + localId); |
|
387 |
return guid; |
|
388 |
} |
|
389 |
|
|
390 |
catch(IOException e) { |
|
391 |
throw new ServiceFailure("1310", "Error updating document in CrudService: " + e.getMessage()); |
|
392 |
} |
|
393 |
catch( McdbDocNotFoundException e) { |
|
394 |
throw new ServiceFailure("1310", "Error updating document in CrudService: " + e.getMessage()); |
|
395 |
} |
|
396 |
catch( InvalidRequest e) { |
|
397 |
throw new ServiceFailure("1310", "Error updating document in CrudService: " + e.getMessage()); |
|
398 |
} |
|
399 |
} |
|
400 |
|
|
401 |
/** |
|
402 |
* set access permissions on both the science metadata and system metadata |
|
403 |
*/ |
|
404 |
public void setAccess(AuthToken token, Identifier id, String principal, String permission, |
|
405 |
String permissionType, String permissionOrder) |
|
406 |
throws ServiceFailure |
|
407 |
{ |
|
408 |
setAccess(token, id, principal, permission, permissionType, permissionOrder, true); |
|
409 |
} |
|
410 |
|
|
411 |
/** |
|
412 |
* set access control on the doc |
|
413 |
* @param token |
|
414 |
* @param id |
|
415 |
* @param principal |
|
416 |
* @param permission |
|
417 |
*/ |
|
418 |
public void setAccess(AuthToken token, Identifier id, String principal, int permission, |
|
419 |
String permissionType, String permissionOrder, boolean setSystemMetadata) |
|
420 |
throws ServiceFailure |
|
421 |
{ |
|
422 |
String perm = ""; |
|
423 |
if(permission >= 4) |
|
424 |
{ |
|
425 |
perm = "read"; |
|
426 |
} |
|
427 |
if(permission >= 6) |
|
428 |
{ |
|
429 |
perm = "write"; |
|
430 |
} |
|
431 |
//logCrud.debug("perm in setAccess: " + perm); |
|
432 |
//logCrud.debug("permission in setAccess: " + permission); |
|
433 |
setAccess(token, id, principal, perm, permissionType, permissionOrder, |
|
434 |
setSystemMetadata); |
|
435 |
|
|
436 |
} |
|
437 |
|
|
438 |
/** |
|
439 |
* set the permission on the document |
|
440 |
* @param token |
|
441 |
* @param principal |
|
442 |
* @param permission |
|
443 |
* @param permissionType |
|
444 |
* @param permissionOrder |
|
445 |
* @return |
|
446 |
*/ |
|
447 |
public void setAccess(AuthToken token, Identifier id, String principal, String permission, |
|
448 |
String permissionType, String permissionOrder, boolean setSystemMetadata) |
|
449 |
throws ServiceFailure |
|
450 |
{ |
|
451 |
/* TODO: |
|
452 |
* This is also not part of the D1 Crud spec. This method is needed for |
|
453 |
* systems such as metacat where access to objects is controlled by |
|
454 |
* and ACL. Higher level decisions need to be made about how this |
|
455 |
* should work within D1. |
|
456 |
*/ |
|
457 |
try |
|
458 |
{ |
|
459 |
final SessionData sessionData = getSessionData(token); |
|
460 |
if(sessionData == null) |
|
461 |
{ |
|
462 |
throw new ServiceFailure("1000", "User must be logged in to set access."); |
|
463 |
} |
|
464 |
IdentifierManager im = IdentifierManager.getInstance(); |
|
465 |
String docid = im.getLocalId(id.getValue()); |
|
466 |
|
|
467 |
String permNum = "0"; |
|
468 |
if(permission.equals("read")) |
|
469 |
{ |
|
470 |
permNum = "4"; |
|
471 |
} |
|
472 |
else if(permission.equals("write")) |
|
473 |
{ |
|
474 |
permNum = "6"; |
|
475 |
} |
|
476 |
logCrud.debug("user " + sessionData.getUserName() + |
|
477 |
" is setting access level " + permNum + " for permission " + |
|
478 |
permissionType + " on doc with localid " + docid); |
|
479 |
handler.setAccess(metacatUrl, sessionData.getUserName(), docid, |
|
480 |
principal, permNum, permissionType, permissionOrder); |
|
481 |
|
|
482 |
String username = "public"; |
|
483 |
if(sessionData != null) |
|
484 |
{ |
|
485 |
username = sessionData.getUserName(); |
|
486 |
} |
|
487 |
EventLog.getInstance().log(metacatUrl, |
|
488 |
username, im.getLocalId(id.getValue()), "setAccess"); |
|
489 |
logCrud.info("setAccess"); |
|
490 |
} |
|
491 |
catch(Exception e) |
|
492 |
{ |
|
493 |
e.printStackTrace(); |
|
494 |
throw new ServiceFailure("1000", "Could not set access on the document with id " + id.getValue()); |
|
495 |
} |
|
496 |
} |
|
497 |
|
|
498 |
/** |
|
499 |
* Retrieve the list of objects present on the MN that match the calling |
|
500 |
* parameters. This method is required to support the process of Member |
|
501 |
* Node synchronization. At a minimum, this method should be able to |
|
502 |
* return a list of objects that match: |
|
503 |
* startTime <= SystemMetadata.dateSysMetadataModified |
|
504 |
* but is expected to also support date range (by also specifying endTime), |
|
505 |
* and should also support slicing of the matching set of records by |
|
506 |
* indicating the starting index of the response (where 0 is the index |
|
507 |
* of the first item) and the count of elements to be returned. |
|
508 |
* |
|
509 |
* If startTime or endTime is null, the query is not restricted by that parameter. |
|
510 |
* |
|
511 |
* @see http://mule1.dataone.org/ArchitectureDocs/mn_api_replication.html#MN_replication.listObjects |
|
512 |
* @param token |
|
513 |
* @param startTime |
|
514 |
* @param endTime |
|
515 |
* @param objectFormat |
|
516 |
* @param replicaStatus |
|
517 |
* @param start |
|
518 |
* @param count |
|
519 |
* @return ObjectList |
|
520 |
* @throws NotAuthorized |
|
521 |
* @throws InvalidRequest |
|
522 |
* @throws NotImplemented |
|
523 |
* @throws ServiceFailure |
|
524 |
* @throws InvalidToken |
|
525 |
*/ |
|
526 |
public ObjectList listObjects(AuthToken token, Date startTime, Date endTime, |
|
527 |
ObjectFormat objectFormat, boolean replicaStatus, int start, int count) |
|
528 |
throws NotAuthorized, InvalidRequest, NotImplemented, ServiceFailure, InvalidToken |
|
529 |
{ |
|
530 |
//ObjectList ol = new ObjectList(); |
|
531 |
//final SessionData sessionData = getSessionData(token); |
|
532 |
//int totalAfterQuery = 0; |
|
533 |
|
|
534 |
|
|
535 |
ObjectList objectList = null; |
|
536 |
try { |
|
537 |
objectList = IdentifierManager.getInstance().querySystemMetadata(startTime, endTime, |
|
538 |
objectFormat.getFmtid(), replicaStatus, start, count); |
|
539 |
} catch (Exception e) { |
Also available in: Unified diff
remove CrudService -- replaced by MNodeService and CNodeService