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(Exception e)
972
        {
973
            throw new ServiceFailure("1350", "Could not delete document: " + e.getMessage());
974
        }
975
        
976
        return guid;
977
    }
978

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

    
1080
    /**
1081
     * get the checksum for a document.  defaults to MD5.
1082
     */
1083
    public Checksum getChecksum(AuthToken token, Identifier guid)
1084
            throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, 
1085
            InvalidRequest, NotImplemented 
1086
    {
1087
        logCrud.info("getChecksum");
1088
        return getChecksum(token, guid, "MD5");
1089
    }
1090

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

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

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

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

    
1432
    /** 
1433
     * Determine if a given object should be treated as an XML science metadata
1434
     * object. 
1435
     * 
1436
     * TODO: This test should be externalized in a configuration dictionary rather than being hardcoded.
1437
     * 
1438
     * @param sysmeta the SystemMetadata describig the object
1439
     * @return true if the object should be treated as science metadata
1440
     */
1441
    private boolean isScienceMetadata(SystemMetadata sysmeta) {
1442
        /*boolean scimeta = false;
1443
        //TODO: this should be read from a .properties file instead of being hard coded
1444
        switch (sysmeta.getObjectFormat()) {
1445
            case EML_2_1_0: scimeta = true; break;
1446
            case EML_2_0_1: scimeta = true; break;
1447
            case EML_2_0_0: scimeta = true; break;
1448
            case FGDC_STD_001_1_1999: scimeta = true; break;
1449
            case FGDC_STD_001_1998: scimeta = true; break;
1450
            case NCML_2_2: scimeta = true; break;
1451
            case DSPACE_METS_SIP_1_0: scimeta = true; break;
1452
        }
1453
        
1454
        return scimeta;*/
1455
        
1456
        return MetadataTypeRegister.isMetadataType(sysmeta.getObjectFormat());
1457
    }
1458

    
1459
    /**
1460
     * insert a data doc
1461
     * @param object
1462
     * @param guid
1463
     * @param sessionData
1464
     * @throws ServiceFailure
1465
     * @returns localId of the data object inserted
1466
     */
1467
    private String insertDataObject(InputStream object, Identifier guid, 
1468
            SessionData sessionData) throws ServiceFailure {
1469
        
1470
        String username = "public";
1471
        String[] groups = null;
1472
        if(sessionData != null)
1473
        {
1474
          username = sessionData.getUserName();
1475
          groups = sessionData.getGroupNames();
1476
        }
1477

    
1478
        // generate guid/localId pair for object
1479
        logMetacat.debug("Generating a guid/localId mapping");
1480
        IdentifierManager im = IdentifierManager.getInstance();
1481
        String localId = im.generateLocalId(guid.getValue(), 1);
1482

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

    
1546
    /**
1547
     * write a file to a stream
1548
     * @param dir
1549
     * @param fileName
1550
     * @param data
1551
     * @return
1552
     * @throws ServiceFailure
1553
     */
1554
    private File writeStreamToFile(File dir, String fileName, InputStream data) 
1555
        throws ServiceFailure {
1556
        
1557
        File newFile = new File(dir, fileName);
1558
        logMetacat.debug("Filename for write is: " + newFile.getAbsolutePath());
1559

    
1560
        try {
1561
            if (newFile.createNewFile()) {
1562
                // write data stream to desired file
1563
                OutputStream os = new FileOutputStream(newFile);
1564
                long length = IOUtils.copyLarge(data, os);
1565
                os.flush();
1566
                os.close();
1567
            } else {
1568
                logMetacat.debug("File creation failed, or file already exists.");
1569
                throw new ServiceFailure("1190", "File already exists: " + fileName);
1570
            }
1571
        } catch (FileNotFoundException e) {
1572
            logMetacat.debug("FNF: " + e.getMessage());
1573
            throw new ServiceFailure("1190", "File not found: " + fileName + " " 
1574
                    + e.getMessage());
1575
        } catch (IOException e) {
1576
            logMetacat.debug("IOE: " + e.getMessage());
1577
            throw new ServiceFailure("1190", "File was not written: " + fileName 
1578
                    + " " + e.getMessage());
1579
        }
1580

    
1581
        return newFile;
1582
    }
1583

    
1584
    /**
1585
     * insert a systemMetadata doc, return the localId of the sysmeta
1586
     */
1587
    private String insertSystemMetadata(SystemMetadata sysmeta, SessionData sessionData) 
1588
        throws ServiceFailure 
1589
    {
1590
        logMetacat.debug("Starting to insert SystemMetadata...");
1591
    
1592
        // generate guid/localId pair for sysmeta
1593
        Identifier sysMetaGuid = new Identifier();
1594
        sysMetaGuid.setValue(DocumentUtil.generateDocumentId(1));
1595
        sysmeta.setDateSysMetadataModified(new Date());
1596
        logCrud.debug("****inserting new system metadata with modified date " + 
1597
                sysmeta.getDateSysMetadataModified());
1598

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

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

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

    
1978
        //get the document text
1979
        int rev = im.getLatestRevForLocalId(localId);
1980
        Identifier identifier = new Identifier();
1981
        try {
1982
            identifier.setValue(im.getGUID(localId, rev));
1983
            
1984
        } catch (McdbDocNotFoundException mcdbe) { 
1985
            //we're creating a new SM doc for a doc that is not in the identifier table                                       
1986
            //so we need to add it to
1987
            logCrud.debug("No guid in the identifier table.  adding it for " + localId);
1988
            im.createMapping(localId, localId);
1989
            logCrud.debug("Mapping created for " + localId);
1990
            AccessionNumber accNum = new AccessionNumber(localId, "NONE");
1991
            identifier.setValue(im.getGUID(accNum.getDocid(), rev));
1992
        }
1993

    
1994
        logCrud.debug("Creating system metadata for guid " + identifier.getValue());
1995
        InputStream is = this.get(token, identifier);
1996
        SystemMetadata sm = new SystemMetadata();
1997
        
1998
        //set the id
1999
        sm.setIdentifier(identifier);
2000

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

    
2137
        //set the size
2138
        is = this.get(token, identifier);
2139
        sm.setSize(sizeOfStream(is));
2140

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

    
(1-1/4)