Project

General

Profile

« Previous | Next » 

Revision 5286

Added by Matt Jones over 14 years ago

Added support to ResourceHandler to allow the putObject method to use
arbitrary guid strings as input. These strings are examined, and if they
match the Metacat docid format (scope.id.rev), they are used directly. If
the id is a string in another format, a new localId is generated based on
the current time. Either way, a mapping is made into the identifier table
to relate the original guid to the new localId. Modified DocumentUtil to
generate the ids, and MCTest case to use this new utility method (to stay DRY).
Tests were updated to expect these global identifiers in the putObject
method.

View differences:

test/edu/ucsb/nceas/MCTestCase.java
59 59
import edu.ucsb.nceas.metacat.client.MetacatInaccessibleException;
60 60
import edu.ucsb.nceas.metacat.properties.PropertyService;
61 61
import edu.ucsb.nceas.metacat.shared.ServiceException;
62
import edu.ucsb.nceas.metacat.util.DocumentUtil;
62 63
import edu.ucsb.nceas.metacat.util.RequestUtil;
63 64
import edu.ucsb.nceas.utilities.IOUtil;
64 65
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
......
515 516
		} catch (InterruptedException ie) {
516 517
			debug("Could not sleep: " + ie.getMessage());
517 518
		}
518
		
519
		StringBuffer docid = new StringBuffer(prefix);
520
		docid.append(".");
521 519

  
522
		// Create a calendar to get the date formatted properly
523
		String[] ids = TimeZone.getAvailableIDs(-8 * 60 * 60 * 1000);
524
		SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, ids[0]);
525
		pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
526
		pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
527
		Calendar calendar = new GregorianCalendar(pdt);
528
		Date trialTime = new Date();
529
		calendar.setTime(trialTime);
530
		docid.append(calendar.get(Calendar.YEAR));
531
		docid.append(calendar.get(Calendar.DAY_OF_YEAR));
532
		docid.append(calendar.get(Calendar.HOUR_OF_DAY));
533
		docid.append(calendar.get(Calendar.MINUTE));
534
		docid.append(calendar.get(Calendar.SECOND));
535

  
536
		return docid.toString();
520
		return DocumentUtil.generateDocumentId(prefix, 0);
537 521
	}
538 522
	
539 523
	/**
540 524
	 * Insert a document into metacat. The expected result is passed as result
541 525
	 */
542

  
543 526
	protected String insertDocumentId(String docid, String docText, boolean result,
544 527
			boolean expectKarmaException) {
545 528
		debug("insertDocumentId() - docid=" + docid + " expectedResult=" + result
test/edu/ucsb/nceas/metacattest/restservice/MetacatRestClientTest.java
25 25
import java.io.IOException;
26 26
import java.io.Reader;
27 27
import java.io.StringReader;
28
import java.util.Calendar;
29
import java.util.Date;
30
import java.util.GregorianCalendar;
31
import java.util.SimpleTimeZone;
32
import java.util.TimeZone;
28 33
import java.util.Vector;
29 34

  
30 35
import junit.framework.Test;
......
204 209
        debug("-------------------------------------------------------"); 
205 210
        try {
206 211
            IdentifierManager im = IdentifierManager.getInstance();
207
            String docid = insertTestDocument();
208
            String guid = "test:"+docid;
209
            im.createMapping(guid, docid);
212
            String guid = insertTestDocument();
210 213
            Reader r =  m.getObject(guid, null);            
211 214
            String doc = IOUtil.getAsString(r, true);
212 215
            doc = doc +"\n";
......
358 361
                    accessBlock, null, null,
359 362
                    null, null);
360 363
            String docid = generateDocumentId();
361
            
364
            debug("Generated id: " + docid);
362 365
    		StringReader sr = new StringReader(emldoc);	
363 366
    		m.login(username,password);
364 367

  
......
368 371
    		debug("response:\n"+response);
369 372
            assertTrue(response.indexOf("success") != -1);
370 373
    		
374
            Thread.sleep(5000);
375

  
371 376
    		sr = new StringReader(emldoc);
372 377
    		debug("\nNow update the document...");
373 378
    		response = m.putObject(docid + ".2",sr,false);    	 
......
375 380
            assertTrue(response.indexOf("success") != -1);
376 381
    		sr.close();
377 382
    		
378
    		Thread.sleep(10000);
383
    		Thread.sleep(5000);
379 384
    		
380 385
    		debug("\nFinally delete the document...");
381 386
    		response = m.deleteObject(docid + ".2");  
......
499 504
          }
500 505
    }
501 506
    
502
    /** Insert a test document, returning the docid that was used. */
507
    /** Insert a test document, returning the identifier that was used. */
503 508
    private String insertTestDocument()
504 509
    {
505 510
        String accessBlock = getAccessBlock("public", true, true,
......
508 513
                null, "http://fake.example.com/somedata", null,
509 514
                accessBlock, null, null,
510 515
                null, null);
511
        String docid = generateDocumentId() + ".1";
516
        //String docid = generateDocumentId() + ".1";
517
        String guid = "testid:" + generateTimeString();
512 518
        StringReader sr = new StringReader(emldoc);        
513 519
        String response;
514 520
        try {
515 521
            m.login(username,password);
516
            response = m.putObject(docid,sr,true);
522
            response = m.putObject(guid, sr, true);
517 523
            debug("response:\n"+response);
518 524
            assertTrue(response.indexOf("success") != -1);
519 525
        } catch (InsufficientKarmaException e) {
......
527 533
        } catch (MetacatAuthException e) {
528 534
            fail(e.getMessage());
529 535
        }
530
        return docid;
536
        return guid;
531 537
    }
538
    
539
    /** Generate a timestamp for use in IDs. */
540
    private String generateTimeString()
541
    {
542
        StringBuffer guid = new StringBuffer();
543

  
544
        // Create a calendar to get the date formatted properly
545
        String[] ids = TimeZone.getAvailableIDs(-8 * 60 * 60 * 1000);
546
        SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, ids[0]);
547
        pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
548
        pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
549
        Calendar calendar = new GregorianCalendar(pdt);
550
        Date trialTime = new Date();
551
        calendar.setTime(trialTime);
552
        guid.append(calendar.get(Calendar.YEAR));
553
        guid.append(calendar.get(Calendar.DAY_OF_YEAR));
554
        guid.append(calendar.get(Calendar.HOUR_OF_DAY));
555
        guid.append(calendar.get(Calendar.MINUTE));
556
        guid.append(calendar.get(Calendar.SECOND));
557
        guid.append(calendar.get(Calendar.MILLISECOND));
558

  
559
        return guid.toString();
560
    }
532 561
}
src/edu/ucsb/nceas/metacat/restservice/ResourceHandler.java
227 227
    private void loadSessionData() {
228 228
        SessionData sessionData = RequestUtil.getSessionData(request);
229 229

  
230
        // TODO: validate the session before allowing these values to be set
230 231
        username = sessionData.getUserName();
231 232
        password = sessionData.getPassword();
232 233
        groupNames = sessionData.getGroupNames();
233 234
        sessionId = sessionData.getId();
234 235

  
235
        if (username == null)
236
        if (username == null) {
236 237
            username = "public";
238
        }
237 239
    }
238 240

  
239 241
    /**
......
344 346

  
345 347
    /**
346 348
     *  Earthgrid API > Identifier Service > isRegistered Function : calls MetacatHandler > handleIdIsRegisteredAction
347
     * @param identifierId
349
     * @param guid
348 350
     * @throws IOException
349 351
     */
350
    private void isRegistered(String identifierId) throws IOException {
351
        params.put("docid", new String[] { identifierId });
352
    private void isRegistered(String guid) throws IOException
353
    {
354
        
355
        // Look up the localId for this guid
356
        IdentifierManager im = IdentifierManager.getInstance();
357
        String localId = "";
358
        try {
359
            localId = im.getLocalId(guid);
360
        } catch (McdbDocNotFoundException e) {
361
            // TODO: Need to return the proper DataONE exception
362
        }
363
        
364
        params.put("docid", new String[] { localId });
352 365
        PrintWriter out = response.getWriter();
353 366
        handler.handleIdIsRegisteredAction(out, params, response);
354 367
        out.close();
......
366 379

  
367 380
    /**
368 381
     * Earthgrid API > Identifier Service > getNextRevision Function : calls MetacatHandler > handleGetRevisionAndDocTypeAction
369
     * @param identifierId
382
     * @param guid
370 383
     * @throws IOException
371 384
     */
372
    private void getNextRevision(String identifierId) throws IOException {
373
        params.put("docid", new String[] { identifierId });
385
    private void getNextRevision(String guid) throws IOException 
386
    {
387
        params.put("docid", new String[] { guid });
374 388
        PrintWriter out = response.getWriter();
375 389
        //handler.handleGetRevisionAndDocTypeAction(out, params);
376 390

  
377 391
        try {
378 392
            // Make sure there is a docid
379
            if (identifierId == null || identifierId.equals("")) {
393
            if (guid == null || guid.equals("")) {
380 394
                throw new Exception("User didn't specify docid!");
381
            }//if
395
            }
382 396

  
397
            // Look up the localId for this guid
398
            IdentifierManager im = IdentifierManager.getInstance();
399
            String localId = "";
400
            try {
401
                localId = im.getLocalId(guid);
402
            } catch (McdbDocNotFoundException e) {
403
                // TODO: Need to return the proper DataONE exception
404
            }
405
           
383 406
            // Create a DBUtil object
384 407
            DBUtil dbutil = new DBUtil();
385 408
            // Get a rev and doctype
386 409
            String revAndDocType = dbutil
387
                    .getCurrentRevisionAndDocTypeForGivenDocument(identifierId);
410
                    .getCurrentRevisionAndDocTypeForGivenDocument(localId);
388 411
            int revision = Integer.parseInt(revAndDocType.split(";")[0]) + 1;
389 412

  
390 413
            out.println("<?xml version=\"1.0\"?>");
......
425 448
        try {
426 449
            localId = im.getLocalId(guid);
427 450
        } catch (McdbDocNotFoundException e) {
428
            // Need to return the proper DataONE exception
451
            // TODO: Need to return the proper DataONE exception
429 452
        }
430 453
        
431 454
        // Now use that localId to read the object and return it
......
454 477
    private void query() throws Exception {
455 478
        /*  This block commented out because of the EcoGrid circular dependency.
456 479
         *  For now, query will not be supported until the circularity can be
457
         *  resolved, probably by movind the ecogrid query syntax transformers
480
         *  resolved, probably by moving the ecogrid query syntax transformers
458 481
         *  directly into the Metacat codebase.  MBJ 2010-02-03
459 482
         
460 483
        try {
......
509 532
     */
510 533
    private void putObject(String objectId) throws IOException {
511 534

  
535
        // TODO: This function lacks proper handling of authz and authn, so it
536
        // seems that anyone can insert or update; interacts with 
537
        // loadSessinData(), which doesn't validate the session
538
        
512 539
        String action = request.getParameter(FUNCTION_KEYWORD);
513 540

  
514 541
        if (action.equals(FUNCTION_NAME_UPDATE)
515 542
                || action.equals(FUNCTION_NAME_INSERT)) {
516
            //
543
            
544
            // Check if the objectId exists
545
            IdentifierManager im = IdentifierManager.getInstance();
546
            if (im.identifierExists(objectId)) {
547
                // TODO: return IdentifierNotUnique exception
548
            }
549
            
550
            // TODO: For updates, need to check if the old id exists, and if not throw an exception
551
            
517 552
            // WARNING: This should not be a Reader if we are inserting data
518 553
            // Nor should it be read into a String
519 554
            // so this seems like a latent bug to me (MBJ; 16Mar2010)
......
524 559
                buffer.append(line);
525 560
            }
526 561

  
527
            params.put("docid", new String[] { objectId });
562
            String localId = im.generateLocalId(objectId, 1);
563
            params.put("docid", new String[] { localId });
528 564
            params.put("doctext", new String[] { buffer.toString().trim() });
529 565
            params.put("action", new String[] { action });
530 566

  
......
534 570
                        params, username, groupNames);
535 571
                out.close();
536 572
            } else {
573
                // TODO: throw exception to show lack of credentials
537 574
                printError("Permission denied for user " + username, response);
538 575

  
539 576
            }
540 577
        } else {
578
            // TODO: throw the proper exception to indicate an invalid request
541 579
            printError("Specifiy the operation type.(update or insert)",
542 580
                    response);
543 581
        }
src/edu/ucsb/nceas/metacat/util/DocumentUtil.java
28 28

  
29 29
import java.io.PrintWriter;
30 30
import java.sql.SQLException;
31
import java.util.Calendar;
32
import java.util.Date;
33
import java.util.GregorianCalendar;
31 34
import java.util.Hashtable;
35
import java.util.SimpleTimeZone;
32 36
import java.util.Stack;
37
import java.util.TimeZone;
33 38
import java.util.Vector;
34 39

  
35 40
import javax.servlet.http.HttpServletRequest;
......
60 65
    
61 66
    private static Logger logMetacat = Logger.getLogger(DocumentUtil.class);
62 67
    private static char separator = '.';
63

  
68
    private static String prefix = "autogen";
69
    
64 70
    static {
65 71
        try {
66
        	separator = PropertyService.getProperty("document.accNumSeparator").charAt(0);
72
        	separator = PropertyService.getProperty("document.accNumSeparator").charAt(0);    	
67 73
        } catch (PropertyNotFoundException pnfe) {
68
        	logMetacat.error("DocumentUtil() - Could not retrieve account number separator. " 
74
        	logMetacat.error("DocumentUtil() - Could not retrieve accession number separator. " 
69 75
        			+ "Separator set to '.' : " + pnfe.getMessage());
70 76
        }
77
        try {
78
            prefix = PropertyService.getProperty("document.accNumPrefix");      
79
        } catch (PropertyNotFoundException pnfe) {
80
            logMetacat.error("DocumentUtil() - Could not retrieve accession number prefix. " 
81
                    + "Prefix set to " + prefix + ": " + pnfe.getMessage());
82
        }
71 83
    }
72 84

  
73 85
    /**
......
486 498
    	
487 499
    	out.write(result);
488 500
    }
501
    
502
    /**
503
     * Create a unique docid for use in inserts and updates using the default
504
     * prefix from the document.accNumPrefix property. Does not include the 
505
     * 'revision' part of the id if revision is '0', otherwise sets the 
506
     * revision number to 'revision'.
507
     * 
508
     * @param idPrefix the prefix to be used to construct the scope portion of the docid
509
     * @param revision the integer revision to use for this docid
510
     * @return a String docid based on the current date and time
511
     */
512
    public static String generateDocumentId(int revision) {
513
        return generateDocumentId(prefix, revision);
514
    }
515
    
516
    /**
517
     * Create a unique docid for use in inserts and updates using the prefix
518
     * that is provided. Does not include the 'revision' part of the id if 
519
     * revision is '0', otherwise sets the revision number to 'revision'.
520
     * 
521
     * @param idPrefix the prefix to be used to construct the scope portion of the docid
522
     * @param revision the integer revision to use for this docid
523
     * @return a String docid based on the current date and time
524
     */
525
    public static String generateDocumentId(String idPrefix, int revision)
526
    {
527
        StringBuffer docid = new StringBuffer(idPrefix);
528
        docid.append(".");
489 529

  
530
        // Create a calendar to get the date formatted properly
531
        String[] ids = TimeZone.getAvailableIDs(-8 * 60 * 60 * 1000);
532
        SimpleTimeZone pdt = new SimpleTimeZone(-8 * 60 * 60 * 1000, ids[0]);
533
        pdt.setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
534
        pdt.setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2 * 60 * 60 * 1000);
535
        Calendar calendar = new GregorianCalendar(pdt);
536
        Date trialTime = new Date();
537
        calendar.setTime(trialTime);
538
        docid.append(calendar.get(Calendar.YEAR));
539
        docid.append(calendar.get(Calendar.DAY_OF_YEAR));
540
        docid.append(calendar.get(Calendar.HOUR_OF_DAY));
541
        docid.append(calendar.get(Calendar.MINUTE));
542
        docid.append(calendar.get(Calendar.SECOND));
543
        docid.append(calendar.get(Calendar.MILLISECOND));
544

  
545
        if (revision > 0) {
546
            docid.append(".").append(revision);
547
        }
548
        return docid.toString();
549
    }
490 550
}
src/edu/ucsb/nceas/metacat/IdentifierManager.java
32 32

  
33 33
import edu.ucsb.nceas.metacat.database.DBConnection;
34 34
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
35
import edu.ucsb.nceas.metacat.util.DocumentUtil;
35 36

  
36 37
/**
37 38
 * Manage the relationship between Metacat local identifiers (LocalIDs) that are
......
186 187
            DBConnectionPool.returnDBConnection(dbConn, serialNumber);
187 188
        }
188 189
    }
190

  
191
    /**
192
     * Given a global identifier (guid), create a suitable local identifier that
193
     * follows Metacat's docid semantics and format (scope.id.rev), and create
194
     * a mapping between these two identifiers.  This effectively reserves both
195
     * the global and the local identifier, as they will now be present in the
196
     * identifier mapping table.  If the incoming guid has the syntax of a
197
     * Metacat docid (scope.id.rev), then simply use it.
198
     * 
199
     * @param guid the global string identifier
200
     * @param rev the revision number to be used in the localId
201
     * @return String containing the localId to be used for Metacat operations
202
     */
203
    public String generateLocalId(String guid, int rev) 
204
    {
205
        String localId = "";
206
        boolean conformsToDocidFormat = false;
207
        
208
        // Check if the guid passed in is already in docid (scope.id.rev) format
209
        try {
210
            AccessionNumber acc = new AccessionNumber(guid, "NONE");
211
            if (new Integer(acc.getRev()).intValue() > 0) {
212
                conformsToDocidFormat = true;
213
            }
214
        } catch (NumberFormatException e) {
215
            // No action needed, simply detecting invalid AccessionNumbers
216
        } catch (AccessionNumberException e) {
217
            // No action needed, simply detecting invalid AccessionNumbers
218
        } catch (SQLException e) {
219
            // No action needed, simply detecting invalid AccessionNumbers
220
        }
221
        
222
        if (conformsToDocidFormat) {
223
            // if it conforms, use it for both guid and localId
224
            localId = guid;
225
        } else {
226
            // if not, then generate a new unique localId
227
            localId = DocumentUtil.generateDocumentId(rev);
228
        }
229
        
230
        // Register this new pair in the identifier mapping table
231
        createMapping(guid, localId);
232
        
233
        return localId;
234
    }
189 235
}

Also available in: Unified diff