Project

General

Profile

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.ByteArrayOutputStream;
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

    
34
import java.security.NoSuchAlgorithmException;
35

    
36
import java.sql.SQLException;
37

    
38
import java.text.DateFormat;
39

    
40
import java.util.Calendar;
41
import java.util.Date;
42
import java.util.Enumeration;
43
import java.util.Hashtable;
44
import java.util.List;
45
import java.util.TimeZone;
46
import java.util.Timer;
47
import java.util.TimerTask;
48
import java.util.Vector;
49

    
50
import javax.servlet.http.HttpServletRequest;
51

    
52
import javax.xml.parsers.ParserConfigurationException;
53
import javax.xml.xpath.XPathExpressionException;
54

    
55
import org.apache.commons.io.IOUtils;
56
import org.apache.log4j.Logger;
57

    
58
import org.dataone.eml.DataoneEMLParser;
59
import org.dataone.eml.EMLDocument;
60
import org.dataone.eml.EMLDocument.DistributionMetadata;
61

    
62
import org.dataone.service.exceptions.BaseException;
63
import org.dataone.service.exceptions.IdentifierNotUnique;
64
import org.dataone.service.exceptions.InsufficientResources;
65
import org.dataone.service.exceptions.InvalidRequest;
66
import org.dataone.service.exceptions.InvalidSystemMetadata;
67
import org.dataone.service.exceptions.InvalidToken;
68
import org.dataone.service.exceptions.NotAuthorized;
69
import org.dataone.service.exceptions.NotFound;
70
import org.dataone.service.exceptions.NotImplemented;
71
import org.dataone.service.exceptions.ServiceFailure;
72
import org.dataone.service.exceptions.UnsupportedType;
73

    
74
import org.dataone.service.mn.MemberNodeCrud;
75

    
76
import org.dataone.service.types.AuthToken;
77
import org.dataone.service.types.Checksum;
78
import org.dataone.service.types.ChecksumAlgorithm;
79
import org.dataone.service.types.DescribeResponse;
80
import org.dataone.service.types.Event;
81
import org.dataone.service.types.Identifier;
82
import org.dataone.service.types.Log;
83
import org.dataone.service.types.LogEntry;
84
import org.dataone.service.types.NodeReference;
85
import org.dataone.service.types.ObjectFormat;
86
import org.dataone.service.types.ObjectList;
87
import org.dataone.service.types.Principal;
88
import org.dataone.service.types.SystemMetadata;
89
import org.dataone.service.types.util.ServiceTypeUtil;
90

    
91
import org.jibx.runtime.BindingDirectory;
92
import org.jibx.runtime.IBindingFactory;
93
import org.jibx.runtime.IMarshallingContext;
94
import org.jibx.runtime.IUnmarshallingContext;
95
import org.jibx.runtime.JiBXException;
96

    
97
import org.xml.sax.SAXException;
98

    
99
import edu.ucsb.nceas.metacat.AccessionNumber;
100
import edu.ucsb.nceas.metacat.AccessionNumberException;
101
import edu.ucsb.nceas.metacat.DocumentImpl;
102
import edu.ucsb.nceas.metacat.EventLog;
103
import edu.ucsb.nceas.metacat.IdentifierManager;
104
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
105
import edu.ucsb.nceas.metacat.McdbException;
106
import edu.ucsb.nceas.metacat.MetacatHandler;
107
import edu.ucsb.nceas.metacat.client.InsufficientKarmaException;
108
import edu.ucsb.nceas.metacat.client.rest.MetacatRestClient;
109
import edu.ucsb.nceas.metacat.properties.PropertyService;
110
import edu.ucsb.nceas.metacat.replication.ForceReplicationHandler;
111
import edu.ucsb.nceas.metacat.service.SessionService;
112
import edu.ucsb.nceas.metacat.util.DocumentUtil;
113
import edu.ucsb.nceas.metacat.util.SessionData;
114

    
115
import edu.ucsb.nceas.utilities.ParseLSIDException;
116
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
117

    
118
/**
119
 * 
120
 * Implements DataONE MemberNode CRUD API for Metacat. 
121
 * 
122
 * @author Matthew Jones
123
 */
124
public class CrudService implements MemberNodeCrud
125
{
126
    private static CrudService crudService = null;
127

    
128
    private MetacatHandler handler;
129
    private Hashtable<String, String[]> params;
130
    private Logger logMetacat = null;
131
    private Logger logCrud = null;
132
    
133
    private String metacatUrl;
134
    
135
    /**
136
     * singleton accessor
137
     */
138
    public static CrudService getInstance() 
139
    {
140
      if(crudService == null)
141
      {
142
        crudService = new CrudService();
143
      }
144
      
145
      return crudService;
146
    }
147
    
148
    /**
149
     * Constructor, private for singleton access
150
     */
151
    private CrudService() {
152
        logMetacat = Logger.getLogger(CrudService.class);
153
        logCrud = Logger.getLogger("DataOneLogger");
154
        try
155
        {
156
            String server = PropertyService.getProperty("server.name");
157
            String port = PropertyService.getProperty("server.httpPort");
158
            String context = PropertyService.getProperty("application.context");
159
            metacatUrl = "http://" + server + ":" + port + "/" + context + "/d1";
160
            logMetacat.debug("Initializing CrudService with url " + metacatUrl);
161
        }
162
        catch(Exception e)
163
        {
164
            logMetacat.error("Could not find servlet url in CrudService: " + e.getMessage());
165
            e.printStackTrace();
166
            throw new RuntimeException("Error getting servlet url in CrudService: " + e.getMessage());
167
        }
168
        
169
        params = new Hashtable<String, String[]>();
170
        handler = new MetacatHandler(new Timer());
171
    }
172
    
173
    /**
174
     * return the context url CrudService is using.
175
     */
176
    public String getContextUrl()
177
    {
178
        return metacatUrl;
179
    }
180
    
181
    /**
182
     * Set the context url that this service uses.  It is normally not necessary
183
     * to call this method unless you are trying to connect to a server other
184
     * than the one in which this service is installed.  Otherwise, this value is
185
     * taken from the metacat.properties file (server.name, server.port, application.context).
186
     */
187
    public void setContextUrl(String url)
188
    {
189
        metacatUrl = url;
190
    }
191
    
192
    /**
193
     * set the params for this service from an HttpServletRequest param list
194
     */
195
    public void setParamsFromRequest(HttpServletRequest request)
196
    {
197
        @SuppressWarnings("unchecked")
198
        Enumeration<String> paramlist = request.getParameterNames();
199
        while (paramlist.hasMoreElements()) {
200
            String name = (String) paramlist.nextElement();
201
            String[] value = (String[])request.getParameterValues(name);
202
            params.put(name, value);
203
        }
204
    }
205
    
206
    /**
207
     * Authenticate against metacat and get a token.
208
     * @param username
209
     * @param password
210
     * @return
211
     * @throws ServiceFailure
212
     */
213
    public AuthToken authenticate(String username, String password)
214
      throws ServiceFailure
215
    {
216
        /* TODO:
217
         * This method is not in the original D1 crud spec.  It is highly
218
         * metacat centric.  Higher level decisions need to be made on authentication
219
         * interfaces for D1 nodes.
220
         */
221
        try
222
        {
223
            MetacatRestClient restClient = new MetacatRestClient(getContextUrl());   
224
            String response = restClient.login(username, password);
225
            String sessionid = restClient.getSessionId();
226
            SessionService sessionService = SessionService.getInstance();
227
            sessionService.registerSession(new SessionData(sessionid, username, new String[0], password, "CrudServiceLogin"));
228
            AuthToken token = new AuthToken(sessionid);
229
            EventLog.getInstance().log(metacatUrl,
230
                    username, null, "authenticate");
231
            logCrud.info("authenticate");
232
            return token;
233
        }
234
        catch(Exception e)
235
        {
236
            throw new ServiceFailure("1620", "Error authenticating with metacat: " + e.getMessage());
237
        }
238
    }
239
    
240
    /**
241
     * set the parameter values needed for this request
242
     */
243
    public void setParameter(String name, String[] value)
244
    {
245
        params.put(name, value);
246
    }
247
    
248
    /**
249
     * Generate SystemMetadata for any object in the object store that does
250
     * not already have it.  SystemMetadata documents themselves, are, of course,
251
     * exempt.  This is a utility method for migration of existing object 
252
     * stores to DataONE where SystemMetadata is required for all objects.  See 
253
     * https://trac.dataone.org/ticket/591
254
     * 
255
     * @param token an authtoken with appropriate permissions to read all 
256
     * documents in the object store.  To work correctly, this should probably
257
     * be an adminstrative credential.
258
     */
259
    public void generateMissingSystemMetadata(AuthToken token) {
260
        IdentifierManager im = IdentifierManager.getInstance();
261
        //get the list of ids with no SM
262
        List<String> idList = im.getLocalIdsWithNoSystemMetadata();
263
        for (String localId : idList) { 
264
            //for each id, add a system metadata doc
265
            generateMissingSystemMetadata(token, localId);
266
        }
267
        logCrud.info("generateMissingSystemMetadata(token)");
268
    }
269
    
270
    /**
271
     * Generate SystemMetadata for a particular object with identifier localId.
272
     * This is a utility method for migration of existing objects 
273
     * to DataONE where SystemMetadata is required for all objects.
274
     * 
275
     * @param token an authtoken with appropriate permissions to read all 
276
     *        documents in the object store.  To work correctly, this should
277
     *        be an adminstrative credential.
278
     * @param localId the identifier of the object to be processed
279
     */
280
    public void generateMissingSystemMetadata(AuthToken token, String localId) {
281
        
282
        logCrud.debug("CrudService.generateMissingSystemMetadata() called.");
283
        
284
        logCrud.debug("Creating SystemMetadata for localId " + localId);
285
        try {
286
            //generate required system metadata fields from the document
287
            SystemMetadata sm = createSystemMetadata(localId, token);
288
            
289
            //insert the systemmetadata object
290
            SessionData sessionData = getSessionData(token);
291
            String smlocalid = insertSystemMetadata(sm, sessionData);
292
            logCrud.debug("setting access on SM doc with localid " + smlocalid);
293
            handler.setAccess(metacatUrl, sessionData.getUserName(), smlocalid, "public", "4", "allow", "allowFirst");
294

    
295
            String username = "public";
296
            if (sessionData != null) {
297
                username = sessionData.getUserName();
298
            }
299
            EventLog.getInstance().log(metacatUrl, username, localId, "generateMissingSystemMetadata");
300
        } catch (Exception e) { // TODO: Please don't catch Exception -- it masks bad things
301
            e.printStackTrace();
302
            logCrud.debug("Exception generating missing system metadata: " + e.getMessage());
303
            logMetacat.error("Could not generate missing system metadata: " + e.getMessage());
304
        }
305
        logCrud.info("generateMissingSystemMetadata(token, localId)");
306
    }
307
    
308
    /**
309
     * create an object via the crud interface
310
     */
311
    public Identifier create(AuthToken token, Identifier guid, 
312
            InputStream object, SystemMetadata sysmeta) throws InvalidToken, 
313
            ServiceFailure, NotAuthorized, IdentifierNotUnique, UnsupportedType, 
314
            InsufficientResources, InvalidSystemMetadata, NotImplemented {
315
        logMetacat.debug("Starting CrudService.create()...");
316
        
317
        // authenticate & get user info
318
        SessionData sessionData = getSessionData(token);
319
        String username = "public";
320
        String[] groups = null;
321
        if(sessionData != null)
322
        {
323
            username = sessionData.getUserName();
324
            groups = sessionData.getGroupNames();
325
        }
326
        String localId = null;
327

    
328
        if (username == null || username.equals("public"))
329
        {
330
            //TODO: many of the thrown exceptions do not use the correct error codes
331
            //check these against the docs and correct them
332
            throw new NotAuthorized("1100", "User " + username + " is not authorized to create content." +
333
                    "  If you are not logged in, please do so and retry the request.");
334
        }
335
        
336
        // verify that guid == SystemMetadata.getIdentifier()
337
        logMetacat.debug("Comparing guid|sysmeta_guid: " + guid.getValue() + "|" + sysmeta.getIdentifier().getValue());
338
        if (!guid.getValue().equals(sysmeta.getIdentifier().getValue())) {
339
            throw new InvalidSystemMetadata("1180", 
340
                "GUID in method call (" + guid.getValue() + ") does not match GUID in system metadata (" +
341
                sysmeta.getIdentifier().getValue() + ").");
342
        }
343

    
344
        logMetacat.debug("Checking if identifier exists...");
345
        // Check that the identifier does not already exist
346
        IdentifierManager im = IdentifierManager.getInstance();
347
        if (im.identifierExists(guid.getValue())) {
348
            throw new IdentifierNotUnique("1120", 
349
                "GUID is already in use by an existing object.");
350
        }
351

    
352
        // Check if we are handling metadata or data
353
        boolean isScienceMetadata = isScienceMetadata(sysmeta);
354
        
355
        if (isScienceMetadata) {
356
            // CASE METADATA:
357
            try {
358
                //logCrud.debug("CrudService: inserting document with guid " + guid.getValue());
359
                this.insertDocument(object, guid, sessionData);
360
                localId = im.getLocalId(guid.getValue());
361
            } catch (IOException e) {
362
                String msg = "Could not create string from XML stream: " +
363
                    " " + e.getMessage();
364
                logMetacat.debug(msg);
365
                throw new ServiceFailure("1190", msg);
366
            } catch(Exception e) {
367
                String msg = "Unexpected error in CrudService.create: " + e.getMessage();
368
                logMetacat.debug(msg);
369
                throw new ServiceFailure("1190", msg);
370
            }
371
            
372

    
373
        } else {
374
            // DEFAULT CASE: DATA (needs to be checked and completed)
375
            localId = insertDataObject(object, guid, sessionData);
376
            
377
        }
378

    
379
        // For Metadata and Data, insert the system metadata into the object store too
380
        String sysMetaLocalId = insertSystemMetadata(sysmeta, sessionData);
381
        //get the document info.  add any access params for the sysmeta too
382
        //logCrud.debug("looking for access records to add for system " +
383
        //    "metadata who's parent doc's  local id is " + localId);
384
        try
385
        {
386
            Hashtable<String, Object> h = im.getDocumentInfo(localId.substring(0, localId.lastIndexOf(".")));
387
            Vector v = (Vector)h.get("access");
388
            for(int i=0; i<v.size(); i++)
389
            {
390
                @SuppressWarnings("unchecked")
391
                Hashtable<String, String> ah = (Hashtable<String, String>)v.elementAt(i);
392
                String principal = (String)ah.get("principal_name");
393
                String permission = (String)ah.get("permission");
394
                String permissionType = (String)ah.get("permission_type");
395
                String permissionOrder = (String)ah.get("permission_order");
396
                int perm = new Integer(permission).intValue();
397
                //logCrud.debug("found access record for principal " + principal);
398
                //logCrud.debug("permission: " + perm + " perm_type: " + permissionType + 
399
                //    " perm_order: " + permissionOrder);
400
                this.setAccess(token, guid, principal, perm, permissionType, permissionOrder, true);
401
            }
402
        }
403
        catch(Exception e)
404
        {
405
            logMetacat.error("Error setting permissions on System Metadata object " + 
406
                    " with id " + sysMetaLocalId + ": " + e.getMessage());
407
            //TODO: decide if this error should cancel the entire create or
408
            //if it should continue with just a logged error.
409
        }
410
        
411
        
412
        logMetacat.debug("Returning from CrudService.create()");
413
        EventLog.getInstance().log(metacatUrl,
414
                username, localId, "create");
415
        logCrud.info("create D1GUID:" + guid.getValue() + ":D1SCIMETADATA:" + localId + 
416
                ":D1SYSMETADATA:"+ sysMetaLocalId + ":");
417
        return guid;
418
    }
419
    
420
    /**
421
     * update an existing object with a new object.  Change the system metadata
422
     * to reflect the changes and update it as well.
423
     */
424
    public Identifier update(AuthToken token, Identifier guid, 
425
            InputStream object, Identifier obsoletedGuid, SystemMetadata sysmeta) 
426
            throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique, 
427
            UnsupportedType, InsufficientResources, NotFound, InvalidSystemMetadata, 
428
            NotImplemented {
429
        try
430
        {
431
            SessionData sessionData = getSessionData(token);
432
            
433
            //find the old systemmetadata (sm.old) document id (the one linked to obsoletedGuid)
434
            SystemMetadata sm = getSystemMetadata(token, obsoletedGuid);
435
            //change sm.old's obsoletedBy field 
436
            List<Identifier> l = sm.getObsoletedByList();
437
            l.add(guid);
438
            sm.setObsoletedByList(l);
439
            //update sm.old
440
            updateSystemMetadata(sm, sessionData);
441
            
442
            //change the obsoletes field of the new systemMetadata (sm.new) to point to the id of the old one
443
            sysmeta.addObsolete(obsoletedGuid);
444
            //insert sm.new
445
            String sysMetaLocalId = insertSystemMetadata(sysmeta, sessionData);
446
            String localId;
447
            
448
            boolean isScienceMetadata = isScienceMetadata(sysmeta);
449
            if(isScienceMetadata)
450
            {
451
                //update the doc
452
                localId = updateDocument(object, obsoletedGuid, guid, sessionData, false);
453
            }
454
            else
455
            {
456
                //update a data file, not xml
457
                localId = insertDataObject(object, guid, sessionData);
458
            }
459
            
460
            IdentifierManager im = IdentifierManager.getInstance();
461
            String username = "public";
462
            if(sessionData != null)
463
            {
464
                username = sessionData.getUserName();
465
            }
466
            EventLog.getInstance().log(metacatUrl,
467
                    username, im.getLocalId(guid.getValue()), "update");
468
            logCrud.info("update D1GUID:" + guid.getValue() + ":D1SCIMETADATA:" + localId + 
469
                    ":D1SYSMETADATA:"+ sysMetaLocalId + ":");
470
            return guid;
471
        }
472
        catch(Exception e)
473
        {
474
            throw new ServiceFailure("1310", "Error updating document in CrudService: " + e.getMessage());
475
        }
476
    }
477
    
478
    /**
479
     * set access permissions on both the science metadata and system metadata
480
     */
481
    public void setAccess(AuthToken token, Identifier id, String principal, String permission,
482
            String permissionType, String permissionOrder)
483
      throws ServiceFailure
484
    {
485
        setAccess(token, id, principal, permission, permissionType, permissionOrder, true);
486
    }
487
    
488
    /**
489
     * set access control on the doc
490
     * @param token
491
     * @param id
492
     * @param principal
493
     * @param permission
494
     */
495
    public void setAccess(AuthToken token, Identifier id, String principal, int permission,
496
      String permissionType, String permissionOrder, boolean setSystemMetadata)
497
      throws ServiceFailure
498
    {
499
        String perm = "";
500
        if(permission >= 4)
501
        {
502
            perm = "read";
503
        }
504
        if(permission >= 6)
505
        {
506
            perm = "write";
507
        }
508
        //logCrud.debug("perm in setAccess: " + perm);
509
        //logCrud.debug("permission in setAccess: " + permission);
510
        setAccess(token, id, principal, perm, permissionType, permissionOrder,
511
                setSystemMetadata);
512
       
513
    }
514
    
515
    /**
516
     * set the permission on the document
517
     * @param token
518
     * @param principal
519
     * @param permission
520
     * @param permissionType
521
     * @param permissionOrder
522
     * @return
523
     */
524
    public void setAccess(AuthToken token, Identifier id, String principal, String permission,
525
            String permissionType, String permissionOrder, boolean setSystemMetadata)
526
      throws ServiceFailure
527
    {
528
        /* TODO:
529
         * This is also not part of the D1 Crud spec.  This method is needed for
530
         * systems such as metacat where access to objects is controlled by
531
         * and ACL.  Higher level decisions need to be made about how this
532
         * should work within D1.
533
         */
534
        try
535
        {
536
            final SessionData sessionData = getSessionData(token);
537
            if(sessionData == null)
538
            {
539
                throw new ServiceFailure("1000", "User must be logged in to set access.");
540
            }
541
            IdentifierManager im = IdentifierManager.getInstance();
542
            String docid = im.getLocalId(id.getValue());
543
        
544
            String permNum = "0";
545
            if(permission.equals("read"))
546
            {
547
                permNum = "4";
548
            }
549
            else if(permission.equals("write"))
550
            {
551
                permNum = "6";
552
            }
553
            logCrud.debug("user " + sessionData.getUserName() + 
554
                    " is setting access level " + permNum + " for permission " + 
555
                    permissionType + " on doc with localid " + docid);
556
            handler.setAccess(metacatUrl, sessionData.getUserName(), docid, 
557
                    principal, permNum, permissionType, permissionOrder);
558
            if(setSystemMetadata)
559
            {
560
                //set the same perms on the system metadata doc
561
                String smlocalid = im.getSystemMetadataLocalId(id.getValue());
562
                logCrud.debug("setting access on SM doc with localid " + smlocalid);
563
                //cs.setAccess(token, smid, principal, permission, permissionType, permissionOrder);
564
                handler.setAccess(metacatUrl, sessionData.getUserName(), smlocalid,
565
                        principal, permNum, permissionType, permissionOrder);
566
            }
567
            String username = "public";
568
            if(sessionData != null)
569
            {
570
                username = sessionData.getUserName();
571
            }
572
            EventLog.getInstance().log(metacatUrl,
573
                    username, im.getLocalId(id.getValue()), "setAccess");
574
            logCrud.info("setAccess");
575
        }
576
        catch(Exception e)
577
        {
578
            e.printStackTrace();
579
            throw new ServiceFailure("1000", "Could not set access on the document with id " + id.getValue());
580
        }
581
    }
582
    
583
    /**
584
     *  Retrieve the list of objects present on the MN that match the calling 
585
     *  parameters. This method is required to support the process of Member 
586
     *  Node synchronization. At a minimum, this method should be able to 
587
     *  return a list of objects that match:
588
     *  startTime <= SystemMetadata.dateSysMetadataModified
589
     *  but is expected to also support date range (by also specifying endTime), 
590
     *  and should also support slicing of the matching set of records by 
591
     *  indicating the starting index of the response (where 0 is the index 
592
     *  of the first item) and the count of elements to be returned.
593
     *  
594
     *  If startTime or endTime is null, the query is not restricted by that parameter.
595
     *  
596
     * @see http://mule1.dataone.org/ArchitectureDocs/mn_api_replication.html#MN_replication.listObjects
597
     * @param token
598
     * @param startTime
599
     * @param endTime
600
     * @param objectFormat
601
     * @param replicaStatus
602
     * @param start
603
     * @param count
604
     * @return ObjectList
605
     * @throws NotAuthorized
606
     * @throws InvalidRequest
607
     * @throws NotImplemented
608
     * @throws ServiceFailure
609
     * @throws InvalidToken
610
     */
611
    public ObjectList listObjects(AuthToken token, Date startTime, Date endTime, 
612
        ObjectFormat objectFormat, boolean replicaStatus, int start, int count)
613
      throws NotAuthorized, InvalidRequest, NotImplemented, ServiceFailure, InvalidToken
614
    {
615
      //ObjectList ol = new ObjectList();
616
      //final SessionData sessionData = getSessionData(token);
617
      //int totalAfterQuery = 0;
618
      
619
      
620
      return IdentifierManager.getInstance().querySystemMetadata(startTime, endTime,
621
              objectFormat, replicaStatus, start, count);
622
      
623
      
624
      /////////////////////////////////////////////////////////////////////////
625
      ///////////////// OLD CODE //////////////////////////////////////////////
626
      /////////////////////////////////////////////////////////////////////////
627
      
628
//      try
629
//      {
630
//          if (PropertyService.getProperty("database.queryCacheOn").equals("true"))
631
//          {
632
//              //System.out.println("the string stored into cache is "+ resultsetBuffer.toString());
633
//              DBQuery.clearQueryResultCache();
634
//          }
635
//      }
636
//      catch (PropertyNotFoundException e1)
637
//      {
638
//          //just don't do anything
639
//      }
640
//      
641
//      try
642
//      {
643
//          //TODO: Milliseconds need to be added to the dateFormat
644
//          System.out.println("=========== Listing Objects =============");
645
//          System.out.println("Current server time is: " + new Date());
646
//          if(startTime != null)
647
//          {
648
//              System.out.println("query start time is " + startTime);
649
//          }
650
//          if(endTime != null)
651
//          {
652
//              System.out.println("query end time is " + endTime);
653
//          }
654
//          params.clear();
655
//          params.put("qformat", new String[] {PropertyService.getProperty("crudService.listObjects.QFormat")});
656
//          params.put("action", new String[] {"squery"});
657
//          params.put("query", new String[] {createListObjectsPathQueryDocument()});
658
//          
659
//          /*System.out.println("query is: metacatUrl: " + metacatUrl + " user: " + sessionData.getUserName() +
660
//                  " sessionid: " + sessionData.getId() + " params: ");
661
//          String url = metacatUrl + "/metacat?action=query&sessionid=" + sessionData.getId();
662
//          Enumeration keys = params.keys();
663
//          while(keys.hasMoreElements())
664
//          {
665
//              String key = (String)keys.nextElement();
666
//              String[] parr = params.get(key);
667
//              for(int i=0; i<parr.length; i++)
668
//              {
669
//                  System.out.println("param " + key + ": " + parr[i]);
670
//                  url += "&" + key + "=" + parr[i] ;
671
//              }
672
//          }
673
//          System.out.println("query url: " + url);
674
//          */
675
//          String username = "public";
676
//          String[] groups = null;
677
//          String sessionid = "";
678
//          if(sessionData != null)
679
//          {
680
//              username = sessionData.getUserName();
681
//              groups = sessionData.getGroupNames();
682
//              sessionid = sessionData.getId();
683
//          }
684
//          
685
//          MetacatResultSet rs = handler.query(metacatUrl, params, username, 
686
//                  groups, sessionid);
687
//          List docs = rs.getDocuments();
688
//          
689
//          System.out.println("query returned " + docs.size() + " documents.");
690
//          Vector<Document> docCopy = new Vector<Document>();
691
//          
692
//          //preparse the list to remove any that don't match the query params
693
//          /* TODO: this type of query/subquery processing is probably not scalable
694
//           * to larger object stores.  This code should be revisited.  The metacat
695
//           * query handler should probably be altered to handle the type of query 
696
//           * done here.
697
//           */ 
698
//          for(int i=0; i<docs.size(); i++)
699
//          {
700
//              Document d = (Document)docs.get(i);
701
//              
702
//              ObjectFormat returnedObjectFormat = ObjectFormat.convert(d.getField("objectFormat"));
703
//              
704
//              if(returnedObjectFormat != null && 
705
//                 objectFormat != null && 
706
//                 !objectFormat.toString().trim().equals(returnedObjectFormat.toString().trim()))
707
//              { //make sure the objectFormat is the one specified
708
//                  continue;
709
//              }
710
//              
711
//              String dateSMM = d.getField("dateSysMetadataModified");
712
//              if((startTime != null || endTime != null) && dateSMM == null)
713
//              {  //if startTime or endTime are not null, we need a date to compare to
714
//                  continue;
715
//              }
716
//              
717
//              //date parse
718
//              Date dateSysMetadataModified = null;
719
//              if(dateSMM != null)
720
//              {
721
//
722
//                  /*                  
723
//                  if(dateSMM.indexOf(".") != -1)
724
//                  {  //strip the milliseconds
725
//                      //TODO: don't do this. we need milliseconds now.
726
//                      //TODO: explore ISO 8601 to figure out milliseconds
727
//                      dateSMM = dateSMM.substring(0, dateSMM.indexOf(".")) + 'Z';
728
//                  }
729
//                  */
730
//                  //System.out.println("dateSMM: " + dateSMM);
731
//                  //dateFormat.setTimeZone(TimeZone.getTimeZone("GMT-0"));
732
//                  try
733
//                  {   //the format we want
734
//                      dateSysMetadataModified = dateFormat.parse(dateSMM);
735
//                  }
736
//                  catch(java.text.ParseException pe)
737
//                  {   //try another legacy format
738
//                      try
739
//                      {
740
//                          DateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.S'Z'");
741
//                          dateFormat2.setTimeZone(TimeZone.getTimeZone("GMT-0"));
742
//                          dateSysMetadataModified = dateFormat2.parse(dateSMM);
743
//                      }
744
//                      catch(java.text.ParseException pe2)
745
//                      {
746
//                          //try another legacy format
747
//                          DateFormat dateFormat3 = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'");
748
//                          dateFormat3.setTimeZone(TimeZone.getTimeZone("GMT-0"));
749
//                          dateSysMetadataModified = dateFormat3.parse(dateSMM);
750
//                      }
751
//                      
752
//                  }                  
753
//              }
754
//              
755
//              /*System.out.println("====================================");
756
//              System.out.println("doc number " + i);
757
//              System.out.println("docid: " + d.docid);
758
//              System.out.println("guid: " + d.getField("identifier").trim());
759
//              System.out.println("dateSMM: " + dateSMM);
760
//              System.out.println("dateSysMetadataModified: " + dateSysMetadataModified);
761
//              System.out.println("startTime: " + startTime);
762
//              System.out.println("endtime: " + endTime);*/
763
//              
764
//              int startDateComparison = 0;
765
//              int endDateComparison = 0;
766
//              if(startTime != null)
767
//              {
768
//                  Calendar zTime = Calendar.getInstance(TimeZone.getTimeZone("GMT-0"));
769
//                  zTime.setTime(startTime);
770
//                  startTime = zTime.getTime();
771
//                  
772
//                  if(dateSysMetadataModified == null)
773
//                  {
774
//                      startDateComparison = -1;
775
//                  }
776
//                  else
777
//                  {
778
//                      startDateComparison = dateSysMetadataModified.compareTo(startTime);
779
//                  }
780
//                  //System.out.println("startDateCom: " + startDateComparison);
781
//              }
782
//              else
783
//              {
784
//                  startDateComparison = 1;
785
//              }
786
//              
787
//              if(endTime != null)
788
//              {
789
//                  Calendar zTime = Calendar.getInstance(TimeZone.getTimeZone("GMT-0"));
790
//                  zTime.setTime(endTime);
791
//                  endTime = zTime.getTime();
792
//                  
793
//                  if(dateSysMetadataModified == null)
794
//                  {
795
//                      endDateComparison = 1;
796
//                  }
797
//                  else
798
//                  {
799
//                      endDateComparison = dateSysMetadataModified.compareTo(endTime);
800
//                  }
801
//                  //System.out.println("endDateCom: " + endDateComparison);
802
//              }
803
//              else
804
//              {
805
//                  endDateComparison = -1;
806
//              }
807
//              
808
//              
809
//              if(startDateComparison < 0 || endDateComparison > 0)
810
//              { 
811
//                  continue;                  
812
//              }
813
//              
814
//              docCopy.add((Document)docs.get(i));
815
//          } //end pre-parse
816
//          
817
//          docs = docCopy;
818
//          totalAfterQuery = docs.size();
819
//          //System.out.println("total after subquery: " + totalAfterQuery);
820
//          
821
//          //make sure we don't run over the end
822
//          int end = start + count;
823
//          if(end > docs.size())
824
//          {
825
//              end = docs.size();
826
//          }
827
//          
828
//          for(int i=start; i<end; i++)
829
//          {
830
//              //get the document from the result
831
//              Document d = (Document)docs.get(i);
832
//              //System.out.println("processing doc " + d.docid);
833
//              
834
//              String dateSMM = d.getField("dateSysMetadataModified");
835
//              //System.out.println("dateSMM: " + dateSMM);
836
//              //System.out.println("parsed date: " + parseDate(dateSMM));
837
//              Date dateSysMetadataModified = null;
838
//              if(dateSMM != null)
839
//              {
840
//                  try
841
//                  {
842
//                      dateSysMetadataModified = parseDate(dateSMM);
843
//                  }
844
//                  catch(Exception e)
845
//                  { //if we fail to parse the date, just ignore the value
846
//                      dateSysMetadataModified = null;
847
//                  }
848
//              }
849
//              ObjectFormat returnedObjectFormat = ObjectFormat.convert(d.getField("objectFormat"));
850
//                
851
//              
852
//              ObjectInfo info = new ObjectInfo();
853
//              //add the fields to the info object
854
//              Checksum cs = new Checksum();
855
//              cs.setValue(d.getField("checksum"));
856
//              String csalg = d.getField("algorithm");
857
//              if(csalg == null)
858
//              {
859
//                  csalg = "MD5";
860
//              }
861
//              ChecksumAlgorithm ca = ChecksumAlgorithm.convert(csalg);
862
//              cs.setAlgorithm(ca);
863
//              info.setChecksum(cs);
864
//              info.setDateSysMetadataModified(dateSysMetadataModified);
865
//              Identifier id = new Identifier();
866
//              id.setValue(d.getField("identifier").trim());
867
//              info.setIdentifier(id);
868
//              info.setObjectFormat(returnedObjectFormat);
869
//              String size = d.getField("size");
870
//              if(size != null)
871
//              {
872
//                  info.setSize(new Long(size.trim()).longValue());
873
//              }
874
//              //add the ObjectInfo to the ObjectList
875
//              //logCrud.info("objectFormat: " + info.getObjectFormat().toString());
876
//              //logCrud.info("id: " + info.getIdentifier().getValue());
877
//              
878
//              if(info.getIdentifier().getValue() != null)
879
//              { //id can be null from tests.  should not happen in production.
880
//                  if((info.getObjectFormat() != null && !info.getObjectFormat().toString().trim().equals("")))
881
//                  { //objectFormat needs to not be null and not be an empty string
882
//                    ol.addObjectInfo(info);
883
//                  }
884
//                  else
885
//                  {
886
//                      logCrud.info("Not adding object with null objectFormat" + info.getIdentifier().getValue().toString());
887
//                  }
888
//              }
889
//             
890
//          }
891
//      }
892
//      catch(Exception e)
893
//      {
894
//          e.printStackTrace();
895
//          logCrud.error("Error creating ObjectList: " + e.getMessage() + " cause: " + e.getCause());
896
//          throw new ServiceFailure("1580", "Error retrieving ObjectList: " + e.getMessage());
897
//      }
898
//      String username = "public";
899
//      if(sessionData != null)
900
//      {
901
//          username = sessionData.getUserName();
902
//      }
903
//      EventLog.getInstance().log(metacatUrl,
904
//              username, null, "read");
905
//      logCrud.info("listObjects");
906
//      if(totalAfterQuery < count)
907
//      {
908
//          count = totalAfterQuery;
909
//      }
910
//      ol.setCount(count);
911
//      ol.setStart(start);
912
//      ol.setTotal(totalAfterQuery);
913
//      return ol;
914
    }
915
    
916
    /**
917
     * Call listObjects with the default values for replicaStatus (true), start (0),
918
     * and count (1000).
919
     * @param token
920
     * @param startTime
921
     * @param endTime
922
     * @param objectFormat
923
     * @return
924
     * @throws NotAuthorized
925
     * @throws InvalidRequest
926
     * @throws NotImplemented
927
     * @throws ServiceFailure
928
     * @throws InvalidToken
929
     */
930
    public ObjectList listObjects(AuthToken token, Date startTime, Date endTime, 
931
        ObjectFormat objectFormat)
932
      throws NotAuthorized, InvalidRequest, NotImplemented, ServiceFailure, InvalidToken
933
    {
934
       return listObjects(token, startTime, endTime, objectFormat, true, 0, 1000);
935
    }
936

    
937
    /**
938
     * Delete a document. 
939
     */
940
    public Identifier delete(AuthToken token, Identifier guid)
941
            throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, 
942
            NotImplemented, InvalidRequest {
943
        logCrud.info("delete");
944
        
945
        if(token == null || token.getToken().equals("publid"))
946
        {
947
            throw new NotAuthorized("1320", "You must be logged in to delete records.");
948
        }
949
        
950
        if(guid == null || guid.getValue().trim().equals(""))
951
        {
952
            throw new InvalidRequest("1322", "No GUID specified in CrudService.delete()");
953
        }
954
        final SessionData sessionData = getSessionData(token);
955
        IdentifierManager manager = IdentifierManager.getInstance();
956
        
957
        String docid;
958
        try
959
        {
960
            docid = manager.getLocalId(guid.getValue());
961
        }
962
        catch(McdbDocNotFoundException mnfe)
963
        {
964
            throw new InvalidRequest("1322", "GUID " + guid + " not found.");
965
        }
966
        
967
        try
968
        {
969
            DocumentImpl.delete(docid, sessionData.getUserName(), sessionData.getGroupNames(), null);
970
        }
971
        catch(SQLException e)
972
        {
973
            throw new ServiceFailure("1350", "Could not delete document: " + e.getMessage());
974
        }
975
        catch(McdbDocNotFoundException e)
976
        {
977
          throw new ServiceFailure("1350", "Could not delete document: " + e.getMessage());
978
        }
979
        catch(InsufficientKarmaException e)
980
        {
981
          throw new ServiceFailure("1350", "Could not delete document: " + e.getMessage());
982
        }
983
        catch(Exception e)
984
        {
985
          throw new ServiceFailure("1350", "Could not delete document: " + e.getMessage());
986
        }
987
        return guid;
988
    }
989

    
990
    /**
991
     * describe a document.  
992
     */
993
    public DescribeResponse describe(AuthToken token, Identifier guid)
994
            throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, 
995
            NotImplemented, InvalidRequest {
996
        logCrud.info("describe");
997
        
998
        if(token == null)
999
        {
1000
            throw new InvalidToken("1370", "Authentication token is null");
1001
        }
1002
        
1003
        if(guid == null || guid.getValue().trim().equals(""))
1004
        {
1005
            throw new InvalidRequest("1362", "Guid is null.  A valid guid is required.");
1006
        }
1007
        
1008
        SystemMetadata sm = getSystemMetadata(token, guid);
1009
        DescribeResponse dr = new DescribeResponse(sm.getObjectFormat(), 
1010
                sm.getSize(), sm.getDateSysMetadataModified(), sm.getChecksum());
1011
        return dr;
1012
    }
1013
    
1014
    /**
1015
     * get a document with a specified guid.
1016
     */
1017
    public InputStream get(AuthToken token, Identifier guid)
1018
            throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, 
1019
            NotImplemented {
1020
        
1021
        // Retrieve the session information from the AuthToken
1022
        // If the session is expired, then the user is 'public'
1023
        if(token == null)
1024
        {
1025
            token = new AuthToken("Public");
1026
        }
1027
        final SessionData sessionData = getSessionData(token);
1028
        
1029
        // Look up the localId for this global identifier
1030
        IdentifierManager im = IdentifierManager.getInstance();
1031
        
1032
        try 
1033
        {
1034
            final String localId = im.getLocalId(guid.getValue());
1035
            InputStream objectStream;
1036
            try 
1037
            {
1038
                String username = "public";
1039
                String[] groups = new String[0];
1040
                if(sessionData != null)
1041
                {
1042
                    username = sessionData.getUserName();
1043
                    groups = sessionData.getGroupNames();
1044
                }
1045
                
1046
                objectStream = readFromMetacat(localId, username, groups);
1047
                
1048
            } catch (PropertyNotFoundException e) {
1049
                e.printStackTrace();
1050
                throw new ServiceFailure("1030", "Error getting property from metacat: " + e.getMessage());
1051
            } catch (ClassNotFoundException e) {
1052
                e.printStackTrace();
1053
                throw new ServiceFailure("1030", "Class not found error when reading from metacat: " + e.getMessage());
1054
            } catch (IOException e) {
1055
                e.printStackTrace();
1056
                throw new ServiceFailure("1030", "IOException while reading from metacat: " + e.getMessage());
1057
            } catch (SQLException e) {
1058
                e.printStackTrace();
1059
                throw new ServiceFailure("1030", "SQLException while reading from metacat: " + e.getMessage());
1060
            } catch (McdbException e) {
1061
                e.printStackTrace();
1062
                throw new ServiceFailure("1030", "Metacat DB exception while reading from metacat: " + e.getMessage());
1063
            } catch (ParseLSIDException e) {
1064
                e.printStackTrace();
1065
                throw new NotFound("1020", "LSID parsing exception while reading from metacat: " + e.getMessage());
1066
            } catch (InsufficientKarmaException e) {
1067
                e.printStackTrace();
1068
                throw new NotAuthorized("1000", "User not authorized for get(): " + e.getMessage());
1069
            }
1070
        
1071
        
1072
            String username = "public";
1073
            if(sessionData != null)
1074
            {
1075
                username = sessionData.getUserName();
1076
            }
1077
            
1078
            EventLog.getInstance().log(metacatUrl,
1079
                    username, im.getLocalId(guid.getValue()), "read");
1080
            logCrud.info("get D1GUID:" + guid.getValue() + ":D1SCIMETADATA:" + localId + 
1081
                    ":");
1082
            
1083
            return objectStream;
1084
        } 
1085
        catch (McdbDocNotFoundException e) 
1086
        {
1087
            throw new NotFound("1020", e.getMessage());
1088
        } 
1089
    }
1090

    
1091
    /**
1092
     * get the checksum for a document.  defaults to MD5.
1093
     */
1094
    public Checksum getChecksum(AuthToken token, Identifier guid)
1095
            throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, 
1096
            InvalidRequest, NotImplemented 
1097
    {
1098
        logCrud.info("getChecksum");
1099
        return getChecksum(token, guid, "MD5");
1100
    }
1101

    
1102
    /**
1103
     * get the checksum for a document with the given algorithm
1104
     */
1105
    public Checksum getChecksum(AuthToken token, Identifier guid, 
1106
            String checksumAlgorithm) throws InvalidToken, ServiceFailure, 
1107
            NotAuthorized, NotFound, InvalidRequest, NotImplemented 
1108
    {
1109
        logCrud.info("getChecksum");
1110
        SystemMetadata sm = getSystemMetadata(token, guid);
1111
        Checksum cs = sm.getChecksum();
1112
        if(cs.getAlgorithm().toString().equals(checksumAlgorithm))
1113
        {
1114
            return cs;
1115
        }
1116
        else
1117
        {
1118
            if(checksumAlgorithm == null)
1119
            {
1120
                checksumAlgorithm = "MD5";
1121
            }
1122
            InputStream docStream = get(token, guid);
1123
            String checksum;
1124
            try
1125
            {
1126
                checksum = checksum(docStream, checksumAlgorithm);
1127
            }
1128
            catch(Exception e)
1129
            {
1130
                throw new ServiceFailure("1410", "Error getting checksum: " + e.getMessage());
1131
            }
1132
            Checksum c = new Checksum();
1133
            c.setAlgorithm(ChecksumAlgorithm.convert(checksumAlgorithm));
1134
            c.setValue(checksum);
1135
            return c;
1136
        }
1137
    }
1138

    
1139
    /**
1140
     * get log records.  
1141
     */
1142
    public Log getLogRecords(AuthToken token, Date fromDate, Date toDate, Event event)
1143
            throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest, 
1144
            NotImplemented 
1145
    {
1146
        /*System.out.println("=================== Getting log records ===================");
1147
        System.out.println("Current server time is: " + new Date());
1148
        if(fromDate != null)
1149
        {
1150
          System.out.println("query start time is " + fromDate);
1151
        }
1152
        if(toDate != null)
1153
        {
1154
          System.out.println("query end time is " + toDate);
1155
        }*/
1156
        Log log = new Log();
1157
        Vector<LogEntry> logs = new Vector<LogEntry>();
1158
        IdentifierManager im = IdentifierManager.getInstance();
1159
        EventLog el = EventLog.getInstance();
1160
        if(fromDate == null)
1161
        {
1162
            //System.out.println("setting fromdate from null");
1163
            fromDate = new Date(1);
1164
        }
1165
        if(toDate == null)
1166
        {
1167
            //System.out.println("setting todate from null");
1168
            toDate = new Date();
1169
        }
1170
        
1171
        //System.out.println("fromDate: " + fromDate);
1172
        //System.out.println("toDate: " + toDate);
1173
        
1174
        String report = el.getReport(null, null, null, null, 
1175
                new java.sql.Timestamp(fromDate.getTime()), 
1176
                new java.sql.Timestamp(toDate.getTime()), false);
1177
        
1178
        //System.out.println("report: " + report);
1179
        
1180
        String logEntry = "<logEntry>";
1181
        String endLogEntry = "</logEntry>";
1182
        int startIndex = 0;
1183
        int foundIndex = report.indexOf(logEntry, startIndex);
1184
        while(foundIndex != -1)
1185
        {
1186
            //parse out each entry
1187
            int endEntryIndex = report.indexOf(endLogEntry, foundIndex);
1188
            String entry = report.substring(foundIndex, endEntryIndex);
1189
            //System.out.println("entry: " + entry);
1190
            startIndex = endEntryIndex + endLogEntry.length();
1191
            foundIndex = report.indexOf(logEntry, startIndex);
1192
            
1193
            String entryId = getLogEntryField("entryid", entry);
1194
            String ipAddress = getLogEntryField("ipAddress", entry);
1195
            String principal = getLogEntryField("principal", entry);
1196
            String docid = getLogEntryField("docid", entry);
1197
            String eventS = getLogEntryField("event", entry);
1198
            String dateLogged = getLogEntryField("dateLogged", entry);
1199
            
1200
            LogEntry le = new LogEntry();
1201
            
1202
            Event e = Event.convert(eventS);
1203
            if(e == null)
1204
            { //skip any events that are not Dataone Crud events
1205
                continue;
1206
            }
1207
            le.setEvent(e);
1208
            Identifier entryid = new Identifier();
1209
            entryid.setValue(entryId);
1210
            le.setEntryId(entryid);
1211
            Identifier identifier = new Identifier();
1212
            try
1213
            {
1214
                //System.out.println("converting docid '" + docid + "' to a guid.");
1215
                if(docid == null || docid.trim().equals("") || docid.trim().equals("null"))
1216
                {
1217
                    continue;
1218
                }
1219
                docid = docid.substring(0, docid.lastIndexOf("."));
1220
                identifier.setValue(im.getGUID(docid, im.getLatestRevForLocalId(docid)));
1221
            }
1222
            catch(Exception ex)
1223
            { //try to get the guid, if that doesn't work, just use the local id
1224
                //throw new ServiceFailure("1030", "Error getting guid for localId " + 
1225
                //        docid + ": " + ex.getMessage());\
1226
                
1227
                //skip it if the guid can't be found
1228
                continue;
1229
            }
1230
            
1231
            le.setIdentifier(identifier);
1232
            le.setIpAddress(ipAddress);
1233
            Calendar c = Calendar.getInstance();
1234
            String year = dateLogged.substring(0, 4);
1235
            String month = dateLogged.substring(5, 7);
1236
            String date = dateLogged.substring(8, 10);
1237
            //System.out.println("year: " + year + " month: " + month + " day: " + date);
1238
            c.set(new Integer(year).intValue(), new Integer(month).intValue(), new Integer(date).intValue());
1239
            Date logDate = c.getTime();
1240
            le.setDateLogged(logDate);
1241
            NodeReference memberNode = new NodeReference();
1242
            memberNode.setValue(ipAddress);
1243
            le.setMemberNode(memberNode);
1244
            Principal princ = new Principal();
1245
            princ.setValue(principal);
1246
            le.setPrincipal(princ);
1247
            le.setUserAgent("metacat/RESTService");
1248
            
1249
            if(event == null)
1250
            {
1251
                logs.add(le);
1252
            }
1253
            
1254
            if(event != null &&
1255
               e.toString().toLowerCase().trim().equals(event.toString().toLowerCase().trim()))
1256
            {
1257
              logs.add(le);
1258
            }
1259
        }
1260
        
1261
        log.setLogEntryList(logs);
1262
        logCrud.info("getLogRecords");
1263
        return log;
1264
    }
1265
    
1266
    /**
1267
     * parse a logEntry and get the relavent field from it
1268
     * @param fieldname
1269
     * @param entry
1270
     * @return
1271
     */
1272
    private String getLogEntryField(String fieldname, String entry)
1273
    {
1274
        String begin = "<" + fieldname + ">";
1275
        String end = "</" + fieldname + ">";
1276
        //System.out.println("looking for " + begin + " and " + end + " in entry " + entry);
1277
        String s = entry.substring(entry.indexOf(begin) + begin.length(), entry.indexOf(end));
1278
        //System.out.println("entry " + fieldname + " : " + s);
1279
        return s;
1280
    }
1281

    
1282
    /**
1283
     * get the system metadata for a document with a specified guid.
1284
     */
1285
public SystemMetadata getSystemMetadata(AuthToken token, Identifier guid)
1286
            throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, 
1287
            InvalidRequest, NotImplemented {
1288
        
1289
        logMetacat.debug("CrudService.getSystemMetadata - for guid: " + guid.getValue());
1290
        
1291
        // Retrieve the session information from the AuthToken
1292
        // If the session is expired, then the user is 'public'
1293
        final SessionData sessionData = getSessionData(token);
1294
                
1295
        try {
1296
            IdentifierManager im = IdentifierManager.getInstance();
1297
            final String localId = im.getSystemMetadataLocalId(guid.getValue());
1298
            InputStream objectStream;
1299
            
1300
            try {
1301
                String username = "public";
1302
                String[] groupnames = null;
1303
                if(sessionData != null)
1304
                {
1305
                    username = sessionData.getUserName();
1306
                    groupnames = sessionData.getGroupNames();
1307
                }
1308
                
1309
                objectStream = readFromMetacat(localId, username, groupnames);
1310
                
1311
            } catch (PropertyNotFoundException e) {
1312
                e.printStackTrace();
1313
                throw new ServiceFailure("1090", "Property not found while reading system metadata from metacat: " + e.getMessage());
1314
            } catch (ClassNotFoundException e) {
1315
                e.printStackTrace();
1316
                throw new ServiceFailure("1090", "Class not found while reading system metadata from metacat: " + e.getMessage());
1317
            } catch (IOException e) {
1318
                e.printStackTrace();
1319
                throw new ServiceFailure("1090", "IOException while reading system metadata from metacat: " + e.getMessage());
1320
            } catch (SQLException e) {
1321
                e.printStackTrace();
1322
                throw new ServiceFailure("1090", "SQLException while reading system metadata from metacat: " + e.getMessage());
1323
            } catch (McdbException e) {
1324
                e.printStackTrace();
1325
                throw new ServiceFailure("1090", "Metacat DB Exception while reading system metadata from metacat: " + e.getMessage());
1326
            } catch (ParseLSIDException e) {
1327
                e.printStackTrace();
1328
                throw new NotFound("1060", "Error parsing LSID while reading system metadata from metacat: " + e.getMessage());
1329
            } catch (InsufficientKarmaException e) {
1330
                e.printStackTrace();
1331
                throw new NotAuthorized("1040", "User not authorized for get() on system metadata: " + e.getMessage());
1332
            }
1333
                        
1334
            // Deserialize the xml to create a SystemMetadata object
1335
            SystemMetadata sysmeta = deserializeSystemMetadata(objectStream);
1336
            String username = "public";
1337
            if(sessionData != null)
1338
            {
1339
                username = sessionData.getUserName();
1340
            }
1341
            EventLog.getInstance().log(metacatUrl,
1342
                    username, im.getLocalId(guid.getValue()), "read");
1343
            logCrud.info("getsystemmetadata D1GUID:" + guid.getValue()  + 
1344
                    ":D1SYSMETADATA:"+ localId + ":");
1345
            return sysmeta;
1346
            
1347
        } catch (McdbDocNotFoundException e) {
1348
            //e.printStackTrace();
1349
            throw new NotFound("1040", e.getMessage());
1350
        }                
1351
    }
1352
    
1353
    /**
1354
     * parse the date in the systemMetadata
1355
     * @param s
1356
     * @return
1357
     * @throws Exception
1358
     */
1359
    public Date parseDate(String s)
1360
      throws Exception
1361
    {
1362
        /* TODO:
1363
         * This method should be replaced by a DateFormatter
1364
         */
1365
        Date d = null;
1366
        int tIndex = s.indexOf("T");
1367
        int zIndex = s.indexOf("Z");
1368
        if(tIndex != -1 && zIndex != -1)
1369
        { //parse a date that looks like 2010-05-18T21:12:54.362Z
1370
            //System.out.println("original date: " + s);
1371
            
1372
            String date = s.substring(0, tIndex);
1373
            String year = date.substring(0, date.indexOf("-"));
1374
            String month = date.substring(date.indexOf("-") + 1, date.lastIndexOf("-"));
1375
            String day = date.substring(date.lastIndexOf("-") + 1, date.length());
1376
            /*System.out.println("date: " + "year: " + new Integer(year).intValue() + 
1377
                    " month: " + new Integer(month).intValue() + " day: " + 
1378
                    new Integer(day).intValue());
1379
            */
1380
            String time = s.substring(tIndex + 1, zIndex);
1381
            String hour = time.substring(0, time.indexOf(":"));
1382
            String minute = time.substring(time.indexOf(":") + 1, time.lastIndexOf(":"));
1383
            String seconds = "00";
1384
            String milliseconds = "00";
1385
            if(time.indexOf(".") != -1)
1386
            {
1387
                seconds = time.substring(time.lastIndexOf(":") + 1, time.indexOf("."));
1388
                milliseconds = time.substring(time.indexOf(".") + 1, time.length());
1389
            }
1390
            else
1391
            {
1392
                seconds = time.substring(time.lastIndexOf(":") + 1, time.length());
1393
            }
1394
            /*System.out.println("time: " + "hour: " + new Integer(hour).intValue() + 
1395
                    " minute: " + new Integer(minute).intValue() + " seconds: " + 
1396
                    new Integer(seconds).intValue() + " milli: " + 
1397
                    new Integer(milliseconds).intValue());*/
1398
            
1399
            //d = DateFormat.getDateTimeInstance().parse(date + " " + time);
1400
            Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT-0")/*TimeZone.getDefault()*/);
1401
            c.set(new Integer(year).intValue(), new Integer(month).intValue() - 1, 
1402
                  new Integer(day).intValue(), new Integer(hour).intValue(), 
1403
                  new Integer(minute).intValue(), new Integer(seconds).intValue());
1404
            c.set(Calendar.MILLISECOND, new Integer(milliseconds).intValue());
1405
            d = new Date(c.getTimeInMillis());
1406
            //System.out.println("d: " + d);
1407
            return d;
1408
        }
1409
        else
1410
        {  //if it's not in the expected format, try the formatter
1411
            return DateFormat.getDateTimeInstance().parse(s);
1412
        }
1413
    }
1414

    
1415
    /*
1416
     * Look up the information on the session using the token provided in
1417
     * the AuthToken.  The Session should have all relevant user information.
1418
     * If the session has expired or is invalid, the 'public' session will
1419
     * be returned, giving the user anonymous access.
1420
     */
1421
    public static SessionData getSessionData(AuthToken token) {
1422
        SessionData sessionData = null;
1423
        String sessionId = "PUBLIC";
1424
        if (token != null) {
1425
            sessionId = token.getToken();
1426
        }
1427
        
1428
        // if the session id is registered in SessionService, get the
1429
        // SessionData for it. Otherwise, use the public session.
1430
        //System.out.println("sessionid: " + sessionId);
1431
        if (sessionId != null &&
1432
            !sessionId.toLowerCase().equals("public") &&
1433
            SessionService.getInstance().isSessionRegistered(sessionId)) 
1434
        {
1435
            sessionData = SessionService.getInstance().getRegisteredSession(sessionId);
1436
        } else {
1437
            sessionData = SessionService.getInstance().getPublicSession();
1438
        }
1439
        
1440
        return sessionData;
1441
    }
1442

    
1443
    /** 
1444
     * Determine if a given object should be treated as an XML science metadata
1445
     * object. 
1446
     * 
1447
     * TODO: This test should be externalized in a configuration dictionary rather than being hardcoded.
1448
     * 
1449
     * @param sysmeta the SystemMetadata describig the object
1450
     * @return true if the object should be treated as science metadata
1451
     */
1452
    private boolean isScienceMetadata(SystemMetadata sysmeta) {
1453
        /*boolean scimeta = false;
1454
        //TODO: this should be read from a .properties file instead of being hard coded
1455
        switch (sysmeta.getObjectFormat()) {
1456
            case EML_2_1_0: scimeta = true; break;
1457
            case EML_2_0_1: scimeta = true; break;
1458
            case EML_2_0_0: scimeta = true; break;
1459
            case FGDC_STD_001_1_1999: scimeta = true; break;
1460
            case FGDC_STD_001_1998: scimeta = true; break;
1461
            case NCML_2_2: scimeta = true; break;
1462
            case DSPACE_METS_SIP_1_0: scimeta = true; break;
1463
        }
1464
        
1465
        return scimeta;*/
1466
        
1467
        return MetadataTypeRegister.isMetadataType(sysmeta.getObjectFormat());
1468
    }
1469

    
1470
    /**
1471
     * insert a data doc
1472
     * @param object
1473
     * @param guid
1474
     * @param sessionData
1475
     * @throws ServiceFailure
1476
     * @returns localId of the data object inserted
1477
     */
1478
    private String insertDataObject(InputStream object, Identifier guid, 
1479
            SessionData sessionData) throws ServiceFailure {
1480
        
1481
        String username = "public";
1482
        String[] groups = null;
1483
        if(sessionData != null)
1484
        {
1485
          username = sessionData.getUserName();
1486
          groups = sessionData.getGroupNames();
1487
        }
1488

    
1489
        // generate guid/localId pair for object
1490
        logMetacat.debug("Generating a guid/localId mapping");
1491
        IdentifierManager im = IdentifierManager.getInstance();
1492
        String localId = im.generateLocalId(guid.getValue(), 1);
1493

    
1494
        try {
1495
            logMetacat.debug("Case DATA: starting to write to disk.");
1496
            if (DocumentImpl.getDataFileLockGrant(localId)) {
1497
    
1498
                // Save the data file to disk using "localId" as the name
1499
                try {
1500
                    String datafilepath = PropertyService.getProperty("application.datafilepath");
1501
    
1502
                    File dataDirectory = new File(datafilepath);
1503
                    dataDirectory.mkdirs();
1504
    
1505
                    File newFile = writeStreamToFile(dataDirectory, localId, object);
1506
    
1507
                    // TODO: Check that the file size matches SystemMetadata
1508
                    //                        long size = newFile.length();
1509
                    //                        if (size == 0) {
1510
                    //                            throw new IOException("Uploaded file is 0 bytes!");
1511
                    //                        }
1512
    
1513
                    // Register the file in the database (which generates an exception
1514
                    // if the localId is not acceptable or other untoward things happen
1515
                    try {
1516
                        logMetacat.debug("Registering document...");
1517
                        DocumentImpl.registerDocument(localId, "BIN", localId,
1518
                                username, groups);
1519
                        logMetacat.debug("Registration step completed.");
1520
                    } catch (SQLException e) {
1521
                        //newFile.delete();
1522
                        logMetacat.debug("SQLE: " + e.getMessage());
1523
                        e.printStackTrace(System.out);
1524
                        throw new ServiceFailure("1190", "Registration failed: " + e.getMessage());
1525
                    } catch (AccessionNumberException e) {
1526
                        //newFile.delete();
1527
                        logMetacat.debug("ANE: " + e.getMessage());
1528
                        e.printStackTrace(System.out);
1529
                        throw new ServiceFailure("1190", "Registration failed: " + e.getMessage());
1530
                    } catch (Exception e) {
1531
                        //newFile.delete();
1532
                        logMetacat.debug("Exception: " + e.getMessage());
1533
                        e.printStackTrace(System.out);
1534
                        throw new ServiceFailure("1190", "Registration failed: " + e.getMessage());
1535
                    }
1536
    
1537
                    logMetacat.debug("Logging the creation event.");
1538
                    EventLog.getInstance().log(metacatUrl,
1539
                            username, localId, "create");
1540
    
1541
                    // Schedule replication for this data file
1542
                    logMetacat.debug("Scheduling replication.");
1543
                    ForceReplicationHandler frh = new ForceReplicationHandler(
1544
                            localId, "create", false, null);
1545
    
1546
                } catch (PropertyNotFoundException e) {
1547
                    throw new ServiceFailure("1190", "Could not lock file for writing:" + e.getMessage());
1548
                }
1549
            }
1550
            return localId;
1551
        } catch (Exception e) {
1552
            // Could not get a lock on the document, so we can not update the file now
1553
            throw new ServiceFailure("1190", "Failed to lock file: " + e.getMessage());
1554
        }
1555
    }
1556

    
1557
    /**
1558
     * write a file to a stream
1559
     * @param dir
1560
     * @param fileName
1561
     * @param data
1562
     * @return
1563
     * @throws ServiceFailure
1564
     */
1565
    private File writeStreamToFile(File dir, String fileName, InputStream data) 
1566
        throws ServiceFailure {
1567
        
1568
        File newFile = new File(dir, fileName);
1569
        logMetacat.debug("Filename for write is: " + newFile.getAbsolutePath());
1570

    
1571
        try {
1572
            if (newFile.createNewFile()) {
1573
                // write data stream to desired file
1574
                OutputStream os = new FileOutputStream(newFile);
1575
                long length = IOUtils.copyLarge(data, os);
1576
                os.flush();
1577
                os.close();
1578
            } else {
1579
                logMetacat.debug("File creation failed, or file already exists.");
1580
                throw new ServiceFailure("1190", "File already exists: " + fileName);
1581
            }
1582
        } catch (FileNotFoundException e) {
1583
            logMetacat.debug("FNF: " + e.getMessage());
1584
            throw new ServiceFailure("1190", "File not found: " + fileName + " " 
1585
                    + e.getMessage());
1586
        } catch (IOException e) {
1587
            logMetacat.debug("IOE: " + e.getMessage());
1588
            throw new ServiceFailure("1190", "File was not written: " + fileName 
1589
                    + " " + e.getMessage());
1590
        }
1591

    
1592
        return newFile;
1593
    }
1594

    
1595
    /**
1596
     * insert a systemMetadata doc, return the localId of the sysmeta
1597
     */
1598
    private String insertSystemMetadata(SystemMetadata sysmeta, SessionData sessionData) 
1599
        throws ServiceFailure 
1600
    {
1601
        logMetacat.debug("Starting to insert SystemMetadata...");
1602
    
1603
        // generate guid/localId pair for sysmeta
1604
        Identifier sysMetaGuid = new Identifier();
1605
        sysMetaGuid.setValue(DocumentUtil.generateDocumentId(1));
1606
        sysmeta.setDateSysMetadataModified(new Date());
1607
        logCrud.debug("****inserting new system metadata with modified date " + 
1608
                sysmeta.getDateSysMetadataModified());
1609

    
1610
        String xml = new String(serializeSystemMetadata(sysmeta).toByteArray());
1611
        logCrud.debug("sysmeta: " + xml);
1612
        String localId = insertDocument(xml, sysMetaGuid, sessionData, true);
1613
        logCrud.debug("sysmeta inserted with localId " + localId);
1614
        //insert the system metadata doc id into the systemmetadata table to 
1615
        //link it to the data or metadata document
1616
        IdentifierManager.getInstance().createSystemMetadataMapping(
1617
                sysmeta, sysMetaGuid.getValue());
1618
        return localId;
1619
    }
1620
    
1621
    /**
1622
     * update a systemMetadata doc
1623
     */
1624
    private void updateSystemMetadata(SystemMetadata sm, SessionData sessionData)
1625
      throws ServiceFailure
1626
    {
1627
        
1628
        logCrud.debug("CrudService.updateSystemMetadata() called.");
1629
        try
1630
        {
1631
            String smId = IdentifierManager.getInstance().getSystemMetadataLocalId(sm.getIdentifier().getValue());
1632
            logCrud.debug("Setting date modified to " + new Date());
1633
            sm.setDateSysMetadataModified(new Date());
1634
            String xml = new String(serializeSystemMetadata(sm).toByteArray());
1635
            String localId = updateDocument(xml, sm.getIdentifier(), null, sessionData, true);
1636
            IdentifierManager.getInstance().updateSystemMetadataMapping(sm.getIdentifier().getValue(), localId);
1637
            IdentifierManager.getInstance().insertAdditionalSystemMetadataFields(
1638
              sm.getDateUploaded().getTime(), 
1639
              sm.getRightsHolder().getValue(),
1640
              sm.getChecksum().getValue(), 
1641
              /*sm.getChecksum().getAlgorithm().toString()*/sm.getChecksum().getAlgorithm().name(), 
1642
              sm.getOriginMemberNode().getValue(), 
1643
              sm.getAuthoritativeMemberNode().getValue(), 
1644
              sm.getDateSysMetadataModified().getTime(), 
1645
              sm.getSubmitter().getValue(), 
1646
              sm.getIdentifier().getValue(), 
1647
              sm.getObjectFormat().toString(), 
1648
              sm.getSize());
1649
                        
1650
        }
1651
        catch(Exception e)
1652
        {
1653
            throw new ServiceFailure("1030", "Error updating system metadata: " + e.getMessage());
1654
        }
1655
    }
1656
    
1657
    private String insertDocument(String xml, Identifier guid, SessionData sessionData)
1658
        throws ServiceFailure
1659
    {
1660
        return insertDocument(xml, guid, sessionData, false);
1661
    }
1662
    
1663
    /**
1664
     * insert a document
1665
     * NOTE: this method shouldn't be used from the update or create() methods.  
1666
     * we shouldn't be putting the science metadata or data objects into memory.
1667
     */
1668
    private String insertDocument(String xml, Identifier guid, SessionData sessionData,
1669
            boolean isSystemMetadata)
1670
        throws ServiceFailure
1671
    {
1672
        return insertOrUpdateDocument(xml, guid, sessionData, "insert", isSystemMetadata);
1673
    }
1674
    
1675
    /**
1676
     * insert a document from a stream
1677
     */
1678
    private String insertDocument(InputStream is, Identifier guid, SessionData sessionData)
1679
      throws IOException, ServiceFailure
1680
    {
1681
        //HACK: change this eventually.  we should not be converting the stream to a string
1682
        String xml = IOUtils.toString(is);
1683
        return insertDocument(xml, guid, sessionData);
1684
    }
1685
    
1686
    /**
1687
     * update a document
1688
     * NOTE: this method shouldn't be used from the update or create() methods.  
1689
     * we shouldn't be putting the science metadata or data objects into memory.
1690
     */
1691
    private String updateDocument(String xml, Identifier obsoleteGuid, 
1692
            Identifier guid, SessionData sessionData, boolean isSystemMetadata)
1693
        throws ServiceFailure
1694
    {
1695
        return insertOrUpdateDocument(xml, obsoleteGuid, sessionData, "update", isSystemMetadata);
1696
    }
1697
    
1698
    /**
1699
     * update a document from a stream
1700
     */
1701
    private String updateDocument(InputStream is, Identifier obsoleteGuid, 
1702
            Identifier guid, SessionData sessionData, boolean isSystemMetadata)
1703
      throws IOException, ServiceFailure
1704
    {
1705
        //HACK: change this eventually.  we should not be converting the stream to a string
1706
        String xml = IOUtils.toString(is);
1707
        String localId = updateDocument(xml, obsoleteGuid, guid, sessionData, isSystemMetadata);
1708
        IdentifierManager im = IdentifierManager.getInstance();
1709
        if(guid != null)
1710
        {
1711
          im.createMapping(guid.getValue(), localId);
1712
        }
1713
        return localId;
1714
    }
1715
    
1716
    /**
1717
     * insert a document, return the id of the document that was inserted
1718
     */
1719
    protected String insertOrUpdateDocument(String xml, Identifier guid, 
1720
            SessionData sessionData, String insertOrUpdate, boolean isSystemMetadata) 
1721
        throws ServiceFailure {
1722
        logMetacat.debug("Starting to insert xml document...");
1723
        IdentifierManager im = IdentifierManager.getInstance();
1724

    
1725
        // generate guid/localId pair for sysmeta
1726
        String localId = null;
1727
        if(insertOrUpdate.equals("insert"))
1728
        {
1729
            localId = im.generateLocalId(guid.getValue(), 1, isSystemMetadata);
1730
        }
1731
        else
1732
        {
1733
            //localid should already exist in the identifier table, so just find it
1734
            try
1735
            {
1736
                logCrud.debug("updating guid " + guid.getValue());
1737
                if(!isSystemMetadata)
1738
                {
1739
                    logCrud.debug("looking in identifier table for guid " + guid.getValue());
1740
                    localId = im.getLocalId(guid.getValue());
1741
                }
1742
                else
1743
                {
1744
                    logCrud.debug("looking in systemmetadata table for guid " + guid.getValue());
1745
                    localId = im.getSystemMetadataLocalId(guid.getValue());
1746
                }
1747
                logCrud.debug("localId: " + localId);
1748
                //increment the revision
1749
                String docid = localId.substring(0, localId.lastIndexOf("."));
1750
                String revS = localId.substring(localId.lastIndexOf(".") + 1, localId.length());
1751
                int rev = new Integer(revS).intValue();
1752
                rev++;
1753
                docid = docid + "." + rev;
1754
                localId = docid;
1755
                logCrud.debug("incremented localId: " + localId);
1756
            }
1757
            catch(McdbDocNotFoundException e)
1758
            {
1759
                throw new ServiceFailure("1030", "CrudService.insertOrUpdateDocument(): " +
1760
                    "guid " + guid.getValue() + " should have been in the identifier table, but it wasn't: " + e.getMessage());
1761
            }
1762
        }
1763
        logMetacat.debug("Metadata guid|localId: " + guid.getValue() + "|" +
1764
                localId);
1765

    
1766
        String[] action = new String[1];
1767
        action[0] = insertOrUpdate;
1768
        params.put("action", action);
1769
        String[] docid = new String[1];
1770
        docid[0] = localId;
1771
        params.put("docid", docid);
1772
        String[] doctext = new String[1];
1773
        doctext[0] = xml;
1774
        logMetacat.debug(doctext[0]);
1775
        params.put("doctext", doctext);
1776
        
1777
        // TODO: refactor handleInsertOrUpdateAction() to not output XML directly
1778
        // onto output stream, or alternatively, capture that and parse it to 
1779
        // generate the right exceptions
1780
        //ByteArrayOutputStream output = new ByteArrayOutputStream();
1781
        //PrintWriter pw = new PrintWriter(output);
1782
        String username = "public";
1783
        String[] groupnames = null;
1784
        if(sessionData != null)
1785
        {
1786
            username = sessionData.getUserName();
1787
            groupnames = sessionData.getGroupNames();
1788
        }
1789
        String result = handler.handleInsertOrUpdateAction(metacatUrl, null, 
1790
                            null, params, username, groupnames);
1791
        if(result.indexOf("<error>") != -1)
1792
        {
1793
            throw new ServiceFailure("1000", "Error inserting or updating document: " + result);
1794
        }
1795
        //String outputS = new String(output.toByteArray());
1796
        logMetacat.debug("CrudService.insertDocument - Metacat returned: " + result);
1797
        logMetacat.debug("Finsished inserting xml document with id " + localId);
1798
        return localId;
1799
    }
1800
    
1801
    /**
1802
     * serialize a dataone type
1803
     */
1804
//    private void serializeServiceType(Class type, Object object, OutputStream out)
1805
//        throws JiBXException
1806
//    {
1807
//        IBindingFactory bfact = BindingDirectory.getFactory(type);
1808
//        IMarshallingContext mctx = bfact.createMarshallingContext();
1809
//        mctx.marshalDocument(object, "UTF-8", null, out);
1810
//    }
1811
    
1812
    /**
1813
     * serialize a system metadata doc
1814
     * @param sysmeta
1815
     * @return
1816
     * @throws ServiceFailure
1817
     */
1818
    public static ByteArrayOutputStream serializeSystemMetadata(SystemMetadata sysmeta) 
1819
        throws ServiceFailure {
1820
        IBindingFactory bfact;
1821
        ByteArrayOutputStream sysmetaOut = null;
1822
        try {
1823
            bfact = BindingDirectory.getFactory(SystemMetadata.class);
1824
            IMarshallingContext mctx = bfact.createMarshallingContext();
1825
            sysmetaOut = new ByteArrayOutputStream();
1826
            mctx.marshalDocument(sysmeta, "UTF-8", null, sysmetaOut);
1827
        } catch (JiBXException e) {
1828
            e.printStackTrace();
1829
            throw new ServiceFailure("1190", "Failed to serialize and insert SystemMetadata: " + e.getMessage());
1830
        }
1831
        
1832
        return sysmetaOut;
1833
    }
1834
    
1835
    /**
1836
     * deserialize a system metadata doc
1837
     * @param xml
1838
     * @return
1839
     * @throws ServiceFailure
1840
     */
1841
    public static SystemMetadata deserializeSystemMetadata(InputStream xml) 
1842
        throws ServiceFailure {
1843
        try {
1844
            IBindingFactory bfact = BindingDirectory.getFactory(SystemMetadata.class);
1845
            IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
1846
            SystemMetadata sysmeta = (SystemMetadata) uctx.unmarshalDocument(xml, null);
1847
            return sysmeta;
1848
        } catch (JiBXException e) {
1849
            e.printStackTrace();
1850
            throw new ServiceFailure("1190", "Failed to deserialize and insert SystemMetadata: " + e.getMessage());
1851
        }    
1852
    }
1853
    
1854
    /**
1855
     * read a document from metacat and return the InputStream
1856
     * 
1857
     * @param localId
1858
     * @param username
1859
     * @param groups
1860
     * @return
1861
     * @throws InsufficientKarmaException
1862
     * @throws ParseLSIDException
1863
     * @throws PropertyNotFoundException
1864
     * @throws McdbException
1865
     * @throws SQLException
1866
     * @throws ClassNotFoundException
1867
     * @throws IOException
1868
     */
1869
    private InputStream readFromMetacat(String localId, String username, String[] groups)
1870
        throws InsufficientKarmaException, ParseLSIDException,
1871
        PropertyNotFoundException, McdbException, SQLException, 
1872
        ClassNotFoundException, IOException
1873
    {
1874
        File tmpDir;
1875
        try
1876
        {
1877
            tmpDir = new File(PropertyService.getProperty("application.tempDir"));
1878
        }
1879
        catch(PropertyNotFoundException pnfe)
1880
        {
1881
            logMetacat.error("ResourceHandler.writeMMPPartstoFiles: " +
1882
                    "application.tmpDir not found.  Using /tmp instead.");
1883
            tmpDir = new File("/tmp");
1884
        }
1885
        Date d = new Date();
1886
        final File outputFile = new File(tmpDir, "metacat.output." + d.getTime());
1887
        FileOutputStream dataSink = new FileOutputStream(outputFile);
1888
        
1889
        handler.readFromMetacat(metacatUrl, null, 
1890
                dataSink, localId, "xml",
1891
                username, 
1892
                groups, true, params);
1893
        
1894
        //set a timer to clean up the temp files
1895
        Timer t = new Timer();
1896
        TimerTask tt = new TimerTask() {
1897
            @Override
1898
            public void run()
1899
            {
1900
                outputFile.delete();
1901
            }
1902
        };
1903
        t.schedule(tt, 20000); //schedule after 20 secs
1904
        
1905
        InputStream objectStream = new FileInputStream(outputFile);
1906
        return objectStream;
1907
    }
1908
    
1909
    /**
1910
     * return an MD5 checksum for the stream
1911
     * @param is
1912
     * @return
1913
     * @throws IOException 
1914
     * @throws NoSuchAlgorithmException 
1915
     */
1916
    public static String checksum(InputStream is) throws NoSuchAlgorithmException, IOException
1917
    {
1918
        return checksum(is, "MD5");
1919
    }
1920
    
1921
    /**
1922
     * produce a checksum for item using the given algorithm
1923
     * @throws IOException 
1924
     * @throws NoSuchAlgorithmException 
1925
     */
1926
    public static String checksum(InputStream is, String algorithm) throws NoSuchAlgorithmException, IOException
1927
    {        
1928
        return ServiceTypeUtil.checksum(is, ChecksumAlgorithm.convert(algorithm)).getValue();
1929
    }
1930
    
1931
    /**
1932
     * parse the metacat date which looks like 2010-06-08 (YYYY-MM-DD) into
1933
     * a proper date object
1934
     * @param date
1935
     * @return
1936
     */
1937
    private Date parseMetacatDate(String date)
1938
    {
1939
        String year = date.substring(0, 4);
1940
        String month = date.substring(5, 7);
1941
        String day = date.substring(8, 10);
1942
        Calendar c = Calendar.getInstance(TimeZone.getDefault());
1943
        c.set(new Integer(year).intValue(), 
1944
              new Integer(month).intValue(), 
1945
              new Integer(day).intValue());
1946
        logCrud.debug("time in parseMetacatDate: " + c.getTime());
1947
        return c.getTime();
1948
    }
1949
    
1950
    /**
1951
     * find the size (in bytes) of a stream
1952
     * @param is
1953
     * @return
1954
     * @throws IOException
1955
     */
1956
    private long sizeOfStream(InputStream is)
1957
        throws IOException
1958
    {
1959
        long size = 0;
1960
        byte[] b = new byte[1024];
1961
        int numread = is.read(b, 0, 1024);
1962
        while(numread != -1)
1963
        {
1964
            size += numread;
1965
            numread = is.read(b, 0, 1024);
1966
        }
1967
        return size;
1968
    }
1969
    
1970
    /**
1971
     * create system metadata with a specified id, doc and format
1972
     * @throws McdbDocNotFoundException 
1973
     * @throws SQLException
1974
     * @throws AccessionNumberException 
1975
     * @throws NumberFormatException 
1976
     * @throws IOException 
1977
     * @throws NoSuchAlgorithmException 
1978
     * @throws PropertyNotFoundException 
1979
     */
1980
    private SystemMetadata createSystemMetadata(String localId, AuthToken token) 
1981
        throws McdbDocNotFoundException, NumberFormatException, AccessionNumberException, 
1982
        SQLException, NoSuchAlgorithmException, IOException, PropertyNotFoundException, BaseException {
1983
        
1984
        logCrud.debug("CrudService.createSystemMetadata() called.");
1985
        
1986
        IdentifierManager im = IdentifierManager.getInstance();
1987
        Hashtable<String, Object> docInfo = im.getDocumentInfo(localId);
1988

    
1989
        //get the document text
1990
        int rev = im.getLatestRevForLocalId(localId);
1991
        Identifier identifier = new Identifier();
1992
        try {
1993
            identifier.setValue(im.getGUID(localId, rev));
1994
            
1995
        } catch (McdbDocNotFoundException mcdbe) { 
1996
            //we're creating a new SM doc for a doc that is not in the identifier table                                       
1997
            //so we need to add it to
1998
            logCrud.debug("No guid in the identifier table.  adding it for " + localId);
1999
            im.createMapping(localId, localId);
2000
            logCrud.debug("Mapping created for " + localId);
2001
            AccessionNumber accNum = new AccessionNumber(localId, "NONE");
2002
            identifier.setValue(im.getGUID(accNum.getDocid(), rev));
2003
        }
2004

    
2005
        logCrud.debug("Creating system metadata for guid " + identifier.getValue());
2006
        InputStream is = this.get(token, identifier);
2007
        SystemMetadata sm = new SystemMetadata();
2008
        
2009
        //set the id
2010
        sm.setIdentifier(identifier);
2011

    
2012
        //set the default object format
2013
        String doctype = (String) docInfo.get("doctype");
2014
        ObjectFormat format = ObjectFormat.convert(doctype);
2015
        if (format == null) {
2016
            if (doctype.trim().equals("BIN")) {
2017
                format = ObjectFormat.OCTET_STREAM;
2018
            } else {
2019
                format = ObjectFormat.convert("text/plain");
2020
            }
2021
        }
2022
        sm.setObjectFormat(format);
2023
        logCrud.debug("The ObjectFormat for " + localId + " is " + format.toString());
2024
        
2025
        // further parse EML documents to get data object format,
2026
        // describes and describedBy information
2027
        if ( format == ObjectFormat.EML_2_0_0 ||
2028
             format == ObjectFormat.EML_2_0_1 ||
2029
             format == ObjectFormat.EML_2_1_0 ) {
2030
          
2031
          try {
2032
            DataoneEMLParser emlParser = DataoneEMLParser.getInstance();
2033
            EMLDocument emlDocument = emlParser.parseDocument(is);
2034
            
2035
            // iterate through the data objects in the EML doc and add sysmeta
2036
           logCrud.debug("The number of data entities is: " +
2037
                         emlDocument.distributionMetadata.size());
2038
                            
2039
           for( int j = 0; j < emlDocument.distributionMetadata.size(); j++ ) {
2040
             
2041
             DistributionMetadata distMetadata = 
2042
               emlDocument.distributionMetadata.elementAt(j);
2043
             String dataDocUrl = distMetadata.url;
2044
             String dataDocMimeType = distMetadata.mimeType;
2045
             String dataDocLocalId = "";
2046
             logCrud.debug("\tData local ID: " + dataDocLocalId);
2047
             logCrud.debug("\tData URL: " + dataDocUrl);
2048
             logCrud.debug("\tData mime: " + dataDocMimeType);
2049
             
2050
             //we only handle ecogrid urls right now
2051
             if ( dataDocUrl.trim().startsWith("ecogrid://knb/") ) {
2052
               dataDocLocalId = 
2053
                 dataDocUrl.substring(dataDocUrl.indexOf("ecogrid://knb/") + 
2054
                 "ecogrid://knb/".length(), dataDocUrl.length());
2055
               
2056
               //set the id
2057
               Identifier dataDocId = new Identifier();
2058
               dataDocId.setValue(dataDocLocalId);
2059
               
2060
               // add describes into EML system metadata
2061
               sm.addDescribe(dataDocId);
2062
               
2063
               SystemMetadata dataSysMeta = new SystemMetadata();
2064
               // check if data system metadata exists
2065
               try {
2066
                 logCrud.debug("Checking for existing system metadata for " + dataDocId.getValue());
2067
                 dataSysMeta = this.getSystemMetadata(token, dataDocId);
2068
                 // add describedBy sysmeta
2069
                 logCrud.debug("Setting describedBy for " + dataDocId.getValue() +
2070
                                  " to " + identifier.getValue());
2071
                 dataSysMeta.addDescribedBy(identifier);
2072
                 dataSysMeta.setObjectFormat(ObjectFormat.convert(dataDocMimeType));
2073
                 this.updateSystemMetadata(dataSysMeta, getSessionData(token));
2074
                 
2075
               } catch ( NotFound nf ) {
2076
                 // System metadata for data doesn't exist
2077
                 logCrud.debug("There was not an existing system metadata " + "document for " + dataDocId.getValue());
2078
                 try {
2079
                   logCrud.debug("Creating a system metadata " + "document for " + dataDocId.getValue());
2080
                   dataSysMeta = this.createSystemMetadata(dataDocLocalId, token);
2081
                   
2082
                   logCrud.debug("Setting describedBy for " + dataDocId.getValue() + " to " + identifier.getValue());
2083
                   dataSysMeta.addDescribedBy(identifier);
2084
                   
2085
                   logCrud.debug("Setting mimeType for " + dataDocId.getValue() + " to " + dataDocMimeType);
2086
                   dataSysMeta.setObjectFormat(ObjectFormat.convert(dataDocMimeType));
2087
                   
2088
                   logCrud.debug("Updating system metadata for " + dataDocId.getValue() + " to " + dataDocMimeType);
2089
                   this.updateSystemMetadata(dataSysMeta, getSessionData(token));
2090
                   
2091
                 } catch ( McdbDocNotFoundException mdnf) {
2092
                   mdnf.printStackTrace();
2093
                   throw mdnf;
2094
                 } catch ( NumberFormatException nfe) {
2095
                   nfe.printStackTrace();
2096
                   throw nfe;
2097
                 } catch ( AccessionNumberException ane) {
2098
                   ane.printStackTrace();
2099
                   throw ane;
2100
                 } catch ( SQLException sqle) {
2101
                   sqle.printStackTrace();
2102
                   throw sqle;
2103
                 } catch ( NoSuchAlgorithmException nsae) {
2104
                   nsae.printStackTrace();
2105
                   throw nsae;
2106
                 } catch ( IOException ioe) {
2107
                   ioe.printStackTrace();
2108
                   throw ioe;
2109
                 } catch ( PropertyNotFoundException pnfe) {
2110
                   pnfe.printStackTrace();
2111
                   throw pnfe;
2112
                 } catch ( BaseException be) {
2113
                   be.printStackTrace();
2114
                   throw be;
2115
                   
2116
                 }
2117
                 
2118
               }
2119
               
2120
             } // end if()
2121
             
2122
           } // end for()
2123
           
2124
          } catch ( ParserConfigurationException pce ) {
2125
            logCrud.debug("There was a problem parsing the EML document. " +
2126
                             "The error message was: " + pce.getMessage());
2127
          
2128
          } catch ( SAXException saxe ) {
2129
            logCrud.debug("There was a problem traversing the EML document. " +
2130
                             "The error message was: " + saxe.getMessage());
2131
          
2132
          } catch ( XPathExpressionException xpee ) {
2133
            logCrud.debug("There was a problem searching the EML document. " +
2134
                             "The error message was: " + xpee.getMessage());
2135
          } // end try
2136
           
2137
        } // end if()
2138
        
2139
        //create the checksum
2140
        is = this.get(token, identifier);
2141
        String checksumS = checksum(is);
2142
        ChecksumAlgorithm ca = ChecksumAlgorithm.convert("MD5");
2143
        Checksum checksum = new Checksum();
2144
        checksum.setValue(checksumS);
2145
        checksum.setAlgorithm(ca);
2146
        sm.setChecksum(checksum);
2147

    
2148
        //set the size
2149
        is = this.get(token, identifier);
2150
        sm.setSize(sizeOfStream(is));
2151

    
2152
        //submitter
2153
        Principal p = new Principal();
2154
        p.setValue((String) docInfo.get("user_owner"));
2155
        sm.setSubmitter(p);
2156
        sm.setRightsHolder(p);
2157
        try {
2158
            Date dateCreated = parseMetacatDate((String) docInfo.get("date_created"));
2159
            sm.setDateUploaded(dateCreated);
2160
            Date dateUpdated = parseMetacatDate((String) docInfo.get("date_updated"));
2161
            sm.setDateSysMetadataModified(dateUpdated);
2162
        } catch (Exception e) {
2163
            logCrud.debug("POSSIBLE ERROR: couldn't parse a date: " + e.getMessage());
2164
            Date dateCreated = new Date();
2165
            sm.setDateUploaded(dateCreated);
2166
            Date dateUpdated = new Date();
2167
            sm.setDateSysMetadataModified(dateUpdated);
2168
        }
2169
        NodeReference nr = new NodeReference();
2170
        nr.setValue(PropertyService.getProperty("dataone.memberNodeId"));
2171
        sm.setOriginMemberNode(nr);
2172
        sm.setAuthoritativeMemberNode(nr);
2173
        
2174
        // TODO: Need to set describes/describedBy
2175
        
2176
        return sm;
2177
    }
2178
    
2179
    /**
2180
     * create the listObjects pathQuery document
2181
     */
2182
//    private String createListObjectsPathQueryDocument()
2183
//        throws PropertyNotFoundException
2184
//    {
2185
//        String s = "<pathquery>";
2186
//        s += "<returndoctype>" + PropertyService.getProperty("crudService.listObjects.ReturnDoctype") + "</returndoctype>";
2187
//        s += "<returnfield>" + PropertyService.getProperty("crudService.listObjects.ReturnField.1") + "</returnfield>";
2188
//        s += "<returnfield>" + PropertyService.getProperty("crudService.listObjects.ReturnField.2") + "</returnfield>";
2189
//        s += "<returnfield>" + PropertyService.getProperty("crudService.listObjects.ReturnField.3") + "</returnfield>";
2190
//        s += "<returnfield>" + PropertyService.getProperty("crudService.listObjects.ReturnField.4") + "</returnfield>";
2191
//        s += "<returnfield>" + PropertyService.getProperty("crudService.listObjects.ReturnField.5") + "</returnfield>";
2192
//        s += "<returnfield>" + PropertyService.getProperty("crudService.listObjects.ReturnField.6") + "</returnfield>";
2193
//        s += "<returnfield>" + PropertyService.getProperty("crudService.listObjects.ReturnField.7") + "</returnfield>";
2194
//        s += "<querygroup operator=\"UNION\"><queryterm casesensitive=\"false\" searchmode=\"contains\">";
2195
//        s += "<value>%</value>"; 
2196
//        s += "<pathexpr>" + PropertyService.getProperty("crudService.listObjects.ReturnField.3") + "</pathexpr>";
2197
//        s += "</queryterm></querygroup></pathquery>";
2198
//  
2199
//        return s;
2200
//    }
2201
}
2202

    
(1-1/4)