Project

General

Profile

1 5298 jones
/**
2
 *  '$RCSfile$'
3
 *  Copyright: 2000 Regents of the University of California and the
4
 *              National Center for Ecological Analysis and Synthesis
5
 *
6 5299 jones
 *   '$Author: $'
7 5298 jones
 *     '$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 5329 jones
import java.io.ByteArrayOutputStream;
26 5319 jones
import java.io.File;
27 5679 berkley
import java.io.FileInputStream;
28 5319 jones
import java.io.FileNotFoundException;
29
import java.io.FileOutputStream;
30 5298 jones
import java.io.IOException;
31
import java.io.InputStream;
32
import java.io.OutputStream;
33 5920 jones
import java.security.NoSuchAlgorithmException;
34 5298 jones
import java.sql.SQLException;
35 5364 berkley
import java.text.DateFormat;
36 5920 jones
import java.util.Calendar;
37
import java.util.Date;
38
import java.util.Enumeration;
39
import java.util.Hashtable;
40
import java.util.List;
41
import java.util.TimeZone;
42
import java.util.Timer;
43
import java.util.TimerTask;
44
import java.util.Vector;
45 5298 jones
46
import javax.servlet.http.HttpServletRequest;
47
48 5319 jones
import org.apache.commons.io.IOUtils;
49
import org.apache.log4j.Logger;
50 5920 jones
import org.dataone.service.exceptions.BaseException;
51 5298 jones
import org.dataone.service.exceptions.IdentifierNotUnique;
52
import org.dataone.service.exceptions.InsufficientResources;
53
import org.dataone.service.exceptions.InvalidRequest;
54
import org.dataone.service.exceptions.InvalidSystemMetadata;
55
import org.dataone.service.exceptions.InvalidToken;
56
import org.dataone.service.exceptions.NotAuthorized;
57
import org.dataone.service.exceptions.NotFound;
58
import org.dataone.service.exceptions.NotImplemented;
59
import org.dataone.service.exceptions.ServiceFailure;
60
import org.dataone.service.exceptions.UnsupportedType;
61
import org.dataone.service.mn.MemberNodeCrud;
62 5920 jones
import org.dataone.service.types.AuthToken;
63
import org.dataone.service.types.Checksum;
64
import org.dataone.service.types.ChecksumAlgorithm;
65
import org.dataone.service.types.DescribeResponse;
66
import org.dataone.service.types.Event;
67
import org.dataone.service.types.Identifier;
68
import org.dataone.service.types.Log;
69
import org.dataone.service.types.LogEntry;
70
import org.dataone.service.types.NodeReference;
71
import org.dataone.service.types.ObjectFormat;
72
import org.dataone.service.types.ObjectList;
73
import org.dataone.service.types.Principal;
74
import org.dataone.service.types.SystemMetadata;
75
import org.dataone.service.types.util.ServiceTypeUtil;
76 5329 jones
import org.jibx.runtime.BindingDirectory;
77
import org.jibx.runtime.IBindingFactory;
78
import org.jibx.runtime.IMarshallingContext;
79 5332 jones
import org.jibx.runtime.IUnmarshallingContext;
80 5329 jones
import org.jibx.runtime.JiBXException;
81 5298 jones
82 5798 berkley
import edu.ucsb.nceas.metacat.AccessionNumber;
83 5319 jones
import edu.ucsb.nceas.metacat.AccessionNumberException;
84
import edu.ucsb.nceas.metacat.DocumentImpl;
85
import edu.ucsb.nceas.metacat.EventLog;
86 5298 jones
import edu.ucsb.nceas.metacat.IdentifierManager;
87
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
88
import edu.ucsb.nceas.metacat.McdbException;
89
import edu.ucsb.nceas.metacat.MetacatHandler;
90
import edu.ucsb.nceas.metacat.client.InsufficientKarmaException;
91 5370 berkley
import edu.ucsb.nceas.metacat.client.rest.MetacatRestClient;
92 5319 jones
import edu.ucsb.nceas.metacat.properties.PropertyService;
93
import edu.ucsb.nceas.metacat.replication.ForceReplicationHandler;
94 5298 jones
import edu.ucsb.nceas.metacat.service.SessionService;
95 5329 jones
import edu.ucsb.nceas.metacat.util.DocumentUtil;
96 5298 jones
import edu.ucsb.nceas.metacat.util.SessionData;
97
import edu.ucsb.nceas.utilities.ParseLSIDException;
98
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
99
100
/**
101
 *
102
 * Implements DataONE MemberNode CRUD API for Metacat.
103
 *
104
 * @author Matthew Jones
105
 */
106 5394 berkley
public class CrudService implements MemberNodeCrud
107
{
108 5337 berkley
    private static CrudService crudService = null;
109 5298 jones
110
    private MetacatHandler handler;
111
    private Hashtable<String, String[]> params;
112 5392 berkley
    private Logger logMetacat = null;
113
    private Logger logCrud = null;
114 5337 berkley
115
    private String metacatUrl;
116 5420 berkley
117 5298 jones
    /**
118 5337 berkley
     * singleton accessor
119
     */
120 5630 berkley
    public static CrudService getInstance()
121 5337 berkley
    {
122
      if(crudService == null)
123
      {
124
        crudService = new CrudService();
125
      }
126
127
      return crudService;
128
    }
129
130
    /**
131 5770 berkley
     * Constructor, private for singleton access
132 5298 jones
     */
133 5763 berkley
    private CrudService() {
134 5337 berkley
        logMetacat = Logger.getLogger(CrudService.class);
135 5392 berkley
        logCrud = Logger.getLogger("DataOneLogger");
136 5337 berkley
        try
137
        {
138
            String server = PropertyService.getProperty("server.name");
139
            String port = PropertyService.getProperty("server.httpPort");
140
            String context = PropertyService.getProperty("application.context");
141 5746 berkley
            metacatUrl = "http://" + server + ":" + port + "/" + context + "/d1";
142 5337 berkley
            logMetacat.debug("Initializing CrudService with url " + metacatUrl);
143
        }
144
        catch(Exception e)
145
        {
146
            logMetacat.error("Could not find servlet url in CrudService: " + e.getMessage());
147
            e.printStackTrace();
148
            throw new RuntimeException("Error getting servlet url in CrudService: " + e.getMessage());
149
        }
150
151
        params = new Hashtable<String, String[]>();
152
        handler = new MetacatHandler(new Timer());
153 5298 jones
    }
154 5337 berkley
155 5298 jones
    /**
156 5337 berkley
     * return the context url CrudService is using.
157 5298 jones
     */
158 5337 berkley
    public String getContextUrl()
159
    {
160
        return metacatUrl;
161
    }
162
163
    /**
164 5394 berkley
     * Set the context url that this service uses.  It is normally not necessary
165
     * to call this method unless you are trying to connect to a server other
166
     * than the one in which this service is installed.  Otherwise, this value is
167
     * taken from the metacat.properties file (server.name, server.port, application.context).
168
     */
169
    public void setContextUrl(String url)
170
    {
171
        metacatUrl = url;
172
    }
173
174
    /**
175 5337 berkley
     * set the params for this service from an HttpServletRequest param list
176
     */
177
    public void setParamsFromRequest(HttpServletRequest request)
178
    {
179 5921 jones
        @SuppressWarnings("unchecked")
180
        Enumeration<String> paramlist = request.getParameterNames();
181 5298 jones
        while (paramlist.hasMoreElements()) {
182 5337 berkley
            String name = (String) paramlist.nextElement();
183
            String[] value = (String[])request.getParameterValues(name);
184 5298 jones
            params.put(name, value);
185
        }
186
    }
187
188 5337 berkley
    /**
189 5370 berkley
     * Authenticate against metacat and get a token.
190
     * @param username
191
     * @param password
192
     * @return
193
     * @throws ServiceFailure
194
     */
195
    public AuthToken authenticate(String username, String password)
196
      throws ServiceFailure
197
    {
198 5466 berkley
        /* TODO:
199
         * This method is not in the original D1 crud spec.  It is highly
200
         * metacat centric.  Higher level decisions need to be made on authentication
201
         * interfaces for D1 nodes.
202
         */
203 5370 berkley
        try
204
        {
205
            MetacatRestClient restClient = new MetacatRestClient(getContextUrl());
206
            String response = restClient.login(username, password);
207
            String sessionid = restClient.getSessionId();
208
            SessionService sessionService = SessionService.getInstance();
209
            sessionService.registerSession(new SessionData(sessionid, username, new String[0], password, "CrudServiceLogin"));
210
            AuthToken token = new AuthToken(sessionid);
211 5383 berkley
            EventLog.getInstance().log(metacatUrl,
212 5384 berkley
                    username, null, "authenticate");
213 5436 berkley
            logCrud.info("authenticate");
214 5370 berkley
            return token;
215
        }
216
        catch(Exception e)
217
        {
218 5624 berkley
            throw new ServiceFailure("1620", "Error authenticating with metacat: " + e.getMessage());
219 5370 berkley
        }
220
    }
221
222
    /**
223 5337 berkley
     * set the parameter values needed for this request
224
     */
225
    public void setParameter(String name, String[] value)
226
    {
227
        params.put(name, value);
228
    }
229
230 5377 berkley
    /**
231
     * Generate SystemMetadata for any object in the object store that does
232
     * not already have it.  SystemMetadata documents themselves, are, of course,
233
     * exempt.  This is a utility method for migration of existing object
234
     * stores to DataONE where SystemMetadata is required for all objects.  See
235
     * https://trac.dataone.org/ticket/591
236 5378 berkley
     *
237
     * @param token an authtoken with appropriate permissions to read all
238
     * documents in the object store.  To work correctly, this should probably
239
     * be an adminstrative credential.
240 5377 berkley
     */
241 5920 jones
    public void generateMissingSystemMetadata(AuthToken token) {
242 5378 berkley
        IdentifierManager im = IdentifierManager.getInstance();
243 5377 berkley
        //get the list of ids with no SM
244 5920 jones
        List<String> idList = im.getLocalIdsWithNoSystemMetadata();
245
        for (String localId : idList) {
246
            //for each id, add a system metadata doc
247
            generateMissingSystemMetadata(token, localId);
248
        }
249
        logCrud.info("generateMissingSystemMetadata(token)");
250
    }
251
252
    /**
253
     * Generate SystemMetadata for a particular object with identifier localId.
254
     * This is a utility method for migration of existing objects
255
     * to DataONE where SystemMetadata is required for all objects.
256
     *
257
     * @param token an authtoken with appropriate permissions to read all
258
     *        documents in the object store.  To work correctly, this should
259
     *        be an adminstrative credential.
260
     * @param localId the identifier of the object to be processed
261
     */
262
    public void generateMissingSystemMetadata(AuthToken token, String localId) {
263
        System.out.println("Creating SystemMetadata for localId " + localId);
264
        try {
265
            //generate required system metadata fields from the document
266
            SystemMetadata sm = createSystemMetadata(localId, token);
267
268
            //insert the systemmetadata object
269
            SessionData sessionData = getSessionData(token);
270
            String smlocalid = insertSystemMetadata(sm, sessionData);
271
            System.out.println("setting access on SM doc with localid " + smlocalid);
272
            handler.setAccess(metacatUrl, sessionData.getUserName(), smlocalid, "public", "4", "allow", "allowFirst");
273
274
            String username = "public";
275
            if (sessionData != null) {
276
                username = sessionData.getUserName();
277 5378 berkley
            }
278 5920 jones
            EventLog.getInstance().log(metacatUrl, username, localId, "generateMissingSystemMetadata");
279
        } catch (Exception e) { // TODO: Please don't catch Exception -- it masks bad things
280
            e.printStackTrace();
281
            System.out.println("Exception generating missing system metadata: " + e.getMessage());
282
            logMetacat.error("Could not generate missing system metadata: " + e.getMessage());
283 5377 berkley
        }
284 5920 jones
        logCrud.info("generateMissingSystemMetadata(token, localId)");
285 5377 berkley
    }
286
287 5378 berkley
    /**
288 5379 berkley
     * create an object via the crud interface
289 5378 berkley
     */
290 5320 jones
    public Identifier create(AuthToken token, Identifier guid,
291 5298 jones
            InputStream object, SystemMetadata sysmeta) throws InvalidToken,
292
            ServiceFailure, NotAuthorized, IdentifierNotUnique, UnsupportedType,
293
            InsufficientResources, InvalidSystemMetadata, NotImplemented {
294 5319 jones
        logMetacat.debug("Starting CrudService.create()...");
295
296 5329 jones
        // authenticate & get user info
297
        SessionData sessionData = getSessionData(token);
298 5431 berkley
        String username = "public";
299
        String[] groups = null;
300
        if(sessionData != null)
301
        {
302
            username = sessionData.getUserName();
303
            groups = sessionData.getGroupNames();
304
        }
305 5383 berkley
        String localId = null;
306 5319 jones
307 5376 berkley
        if (username == null || username.equals("public"))
308
        {
309 5466 berkley
            //TODO: many of the thrown exceptions do not use the correct error codes
310
            //check these against the docs and correct them
311 5624 berkley
            throw new NotAuthorized("1100", "User " + username + " is not authorized to create content." +
312 5376 berkley
                    "  If you are not logged in, please do so and retry the request.");
313
        }
314
315 5319 jones
        // verify that guid == SystemMetadata.getIdentifier()
316 5320 jones
        logMetacat.debug("Comparing guid|sysmeta_guid: " + guid.getValue() + "|" + sysmeta.getIdentifier().getValue());
317 5329 jones
        if (!guid.getValue().equals(sysmeta.getIdentifier().getValue())) {
318 5356 berkley
            throw new InvalidSystemMetadata("1180",
319 5750 berkley
                "GUID in method call (" + guid.getValue() + ") does not match GUID in system metadata (" +
320
                sysmeta.getIdentifier().getValue() + ").");
321 5329 jones
        }
322 5319 jones
323
        logMetacat.debug("Checking if identifier exists...");
324
        // Check that the identifier does not already exist
325 5436 berkley
        IdentifierManager im = IdentifierManager.getInstance();
326 5320 jones
        if (im.identifierExists(guid.getValue())) {
327 5356 berkley
            throw new IdentifierNotUnique("1120",
328 5319 jones
                "GUID is already in use by an existing object.");
329
        }
330
331 5329 jones
        // Check if we are handling metadata or data
332
        boolean isScienceMetadata = isScienceMetadata(sysmeta);
333 5319 jones
334 5329 jones
        if (isScienceMetadata) {
335 5331 jones
            // CASE METADATA:
336
            try {
337 5466 berkley
                //System.out.println("CrudService: inserting document with guid " + guid.getValue());
338 5350 berkley
                this.insertDocument(object, guid, sessionData);
339 5383 berkley
                localId = im.getLocalId(guid.getValue());
340 5331 jones
            } catch (IOException e) {
341
                String msg = "Could not create string from XML stream: " +
342
                    " " + e.getMessage();
343
                logMetacat.debug(msg);
344 5356 berkley
                throw new ServiceFailure("1190", msg);
345 5383 berkley
            } catch(Exception e) {
346
                String msg = "Unexpected error in CrudService.create: " + e.getMessage();
347
                logMetacat.debug(msg);
348
                throw new ServiceFailure("1190", msg);
349 5331 jones
            }
350 5383 berkley
351 5319 jones
352 5329 jones
        } else {
353 5331 jones
            // DEFAULT CASE: DATA (needs to be checked and completed)
354 5460 berkley
            localId = insertDataObject(object, guid, sessionData);
355 5331 jones
356
        }
357 5319 jones
358 5331 jones
        // For Metadata and Data, insert the system metadata into the object store too
359 5441 berkley
        String sysMetaLocalId = insertSystemMetadata(sysmeta, sessionData);
360
        //get the document info.  add any access params for the sysmeta too
361 5466 berkley
        //System.out.println("looking for access records to add for system " +
362
        //    "metadata who's parent doc's  local id is " + localId);
363 5441 berkley
        try
364
        {
365 5444 berkley
            Hashtable<String, Object> h = im.getDocumentInfo(localId.substring(0, localId.lastIndexOf(".")));
366 5441 berkley
            Vector v = (Vector)h.get("access");
367
            for(int i=0; i<v.size(); i++)
368
            {
369 5921 jones
                @SuppressWarnings("unchecked")
370
                Hashtable<String, String> ah = (Hashtable<String, String>)v.elementAt(i);
371 5441 berkley
                String principal = (String)ah.get("principal_name");
372
                String permission = (String)ah.get("permission");
373
                String permissionType = (String)ah.get("permission_type");
374
                String permissionOrder = (String)ah.get("permission_order");
375 5443 berkley
                int perm = new Integer(permission).intValue();
376 5466 berkley
                //System.out.println("found access record for principal " + principal);
377
                //System.out.println("permission: " + perm + " perm_type: " + permissionType +
378
                //    " perm_order: " + permissionOrder);
379 5444 berkley
                this.setAccess(token, guid, principal, perm, permissionType, permissionOrder, true);
380 5441 berkley
            }
381
        }
382
        catch(Exception e)
383
        {
384
            logMetacat.error("Error setting permissions on System Metadata object " +
385
                    " with id " + sysMetaLocalId + ": " + e.getMessage());
386 5466 berkley
            //TODO: decide if this error should cancel the entire create or
387
            //if it should continue with just a logged error.
388 5441 berkley
        }
389
390
391 5319 jones
        logMetacat.debug("Returning from CrudService.create()");
392 5383 berkley
        EventLog.getInstance().log(metacatUrl,
393 5384 berkley
                username, localId, "create");
394 5459 berkley
        logCrud.info("create D1GUID:" + guid.getValue() + ":D1SCIMETADATA:" + localId +
395 5582 berkley
                ":D1SYSMETADATA:"+ sysMetaLocalId + ":");
396 5319 jones
        return guid;
397 5298 jones
    }
398 5353 berkley
399
    /**
400
     * update an existing object with a new object.  Change the system metadata
401
     * to reflect the changes and update it as well.
402
     */
403
    public Identifier update(AuthToken token, Identifier guid,
404
            InputStream object, Identifier obsoletedGuid, SystemMetadata sysmeta)
405
            throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique,
406
            UnsupportedType, InsufficientResources, NotFound, InvalidSystemMetadata,
407
            NotImplemented {
408
        try
409
        {
410
            SessionData sessionData = getSessionData(token);
411
412
            //find the old systemmetadata (sm.old) document id (the one linked to obsoletedGuid)
413
            SystemMetadata sm = getSystemMetadata(token, obsoletedGuid);
414
            //change sm.old's obsoletedBy field
415 5921 jones
            List<Identifier> l = sm.getObsoletedByList();
416 5353 berkley
            l.add(guid);
417
            sm.setObsoletedByList(l);
418
            //update sm.old
419
            updateSystemMetadata(sm, sessionData);
420
421
            //change the obsoletes field of the new systemMetadata (sm.new) to point to the id of the old one
422
            sysmeta.addObsolete(obsoletedGuid);
423
            //insert sm.new
424 5459 berkley
            String sysMetaLocalId = insertSystemMetadata(sysmeta, sessionData);
425
            String localId;
426 5353 berkley
427
            boolean isScienceMetadata = isScienceMetadata(sysmeta);
428
            if(isScienceMetadata)
429
            {
430
                //update the doc
431 5459 berkley
                localId = updateDocument(object, obsoletedGuid, guid, sessionData, false);
432 5353 berkley
            }
433
            else
434
            {
435
                //update a data file, not xml
436 5459 berkley
                localId = insertDataObject(object, guid, sessionData);
437 5353 berkley
            }
438 5383 berkley
439
            IdentifierManager im = IdentifierManager.getInstance();
440 5431 berkley
            String username = "public";
441
            if(sessionData != null)
442
            {
443
                username = sessionData.getUserName();
444
            }
445 5383 berkley
            EventLog.getInstance().log(metacatUrl,
446 5384 berkley
                    username, im.getLocalId(guid.getValue()), "update");
447 5459 berkley
            logCrud.info("update D1GUID:" + guid.getValue() + ":D1SCIMETADATA:" + localId +
448 5582 berkley
                    ":D1SYSMETADATA:"+ sysMetaLocalId + ":");
449 5353 berkley
            return guid;
450
        }
451
        catch(Exception e)
452
        {
453 5624 berkley
            throw new ServiceFailure("1310", "Error updating document in CrudService: " + e.getMessage());
454 5353 berkley
        }
455
    }
456 5359 berkley
457
    /**
458 5521 berkley
     * set access permissions on both the science metadata and system metadata
459
     */
460
    public void setAccess(AuthToken token, Identifier id, String principal, String permission,
461
            String permissionType, String permissionOrder)
462
      throws ServiceFailure
463
    {
464
        setAccess(token, id, principal, permission, permissionType, permissionOrder, true);
465
    }
466
467
    /**
468 5443 berkley
     * set access control on the doc
469
     * @param token
470
     * @param id
471
     * @param principal
472
     * @param permission
473
     */
474
    public void setAccess(AuthToken token, Identifier id, String principal, int permission,
475
      String permissionType, String permissionOrder, boolean setSystemMetadata)
476
      throws ServiceFailure
477
    {
478
        String perm = "";
479 5445 berkley
        if(permission >= 4)
480 5443 berkley
        {
481
            perm = "read";
482
        }
483 5445 berkley
        if(permission >= 6)
484 5443 berkley
        {
485
            perm = "write";
486
        }
487 5466 berkley
        //System.out.println("perm in setAccess: " + perm);
488
        //System.out.println("permission in setAccess: " + permission);
489 5443 berkley
        setAccess(token, id, principal, perm, permissionType, permissionOrder,
490
                setSystemMetadata);
491
492
    }
493
494
    /**
495 5362 berkley
     * set the permission on the document
496
     * @param token
497
     * @param principal
498
     * @param permission
499
     * @param permissionType
500
     * @param permissionOrder
501
     * @return
502
     */
503
    public void setAccess(AuthToken token, Identifier id, String principal, String permission,
504 5424 berkley
            String permissionType, String permissionOrder, boolean setSystemMetadata)
505 5362 berkley
      throws ServiceFailure
506
    {
507 5466 berkley
        /* TODO:
508
         * This is also not part of the D1 Crud spec.  This method is needed for
509
         * systems such as metacat where access to objects is controlled by
510
         * and ACL.  Higher level decisions need to be made about how this
511
         * should work within D1.
512
         */
513 5362 berkley
        try
514
        {
515 5449 berkley
            final SessionData sessionData = getSessionData(token);
516
            if(sessionData == null)
517
            {
518
                throw new ServiceFailure("1000", "User must be logged in to set access.");
519
            }
520 5362 berkley
            IdentifierManager im = IdentifierManager.getInstance();
521
            String docid = im.getLocalId(id.getValue());
522 5449 berkley
523 5362 berkley
            String permNum = "0";
524 5370 berkley
            if(permission.equals("read"))
525 5362 berkley
            {
526
                permNum = "4";
527
            }
528 5370 berkley
            else if(permission.equals("write"))
529 5362 berkley
            {
530
                permNum = "6";
531
            }
532 5424 berkley
            System.out.println("user " + sessionData.getUserName() +
533
                    " is setting access level " + permNum + " for permission " +
534
                    permissionType + " on doc with localid " + docid);
535 5362 berkley
            handler.setAccess(metacatUrl, sessionData.getUserName(), docid,
536
                    principal, permNum, permissionType, permissionOrder);
537 5424 berkley
            if(setSystemMetadata)
538
            {
539
                //set the same perms on the system metadata doc
540
                String smlocalid = im.getSystemMetadataLocalId(id.getValue());
541
                System.out.println("setting access on SM doc with localid " + smlocalid);
542
                //cs.setAccess(token, smid, principal, permission, permissionType, permissionOrder);
543
                handler.setAccess(metacatUrl, sessionData.getUserName(), smlocalid,
544
                        principal, permNum, permissionType, permissionOrder);
545
            }
546 5431 berkley
            String username = "public";
547
            if(sessionData != null)
548
            {
549
                username = sessionData.getUserName();
550
            }
551 5383 berkley
            EventLog.getInstance().log(metacatUrl,
552 5384 berkley
                    username, im.getLocalId(id.getValue()), "setAccess");
553 5392 berkley
            logCrud.info("setAccess");
554 5362 berkley
        }
555
        catch(Exception e)
556
        {
557 5370 berkley
            e.printStackTrace();
558 5362 berkley
            throw new ServiceFailure("1000", "Could not set access on the document with id " + id.getValue());
559
        }
560
    }
561
562
    /**
563 5359 berkley
     *  Retrieve the list of objects present on the MN that match the calling
564
     *  parameters. This method is required to support the process of Member
565
     *  Node synchronization. At a minimum, this method should be able to
566
     *  return a list of objects that match:
567
     *  startTime <= SystemMetadata.dateSysMetadataModified
568
     *  but is expected to also support date range (by also specifying endTime),
569
     *  and should also support slicing of the matching set of records by
570
     *  indicating the starting index of the response (where 0 is the index
571
     *  of the first item) and the count of elements to be returned.
572
     *
573 5364 berkley
     *  If startTime or endTime is null, the query is not restricted by that parameter.
574
     *
575 5359 berkley
     * @see http://mule1.dataone.org/ArchitectureDocs/mn_api_replication.html#MN_replication.listObjects
576
     * @param token
577
     * @param startTime
578
     * @param endTime
579
     * @param objectFormat
580
     * @param replicaStatus
581
     * @param start
582
     * @param count
583
     * @return ObjectList
584
     * @throws NotAuthorized
585
     * @throws InvalidRequest
586
     * @throws NotImplemented
587
     * @throws ServiceFailure
588
     * @throws InvalidToken
589
     */
590
    public ObjectList listObjects(AuthToken token, Date startTime, Date endTime,
591
        ObjectFormat objectFormat, boolean replicaStatus, int start, int count)
592
      throws NotAuthorized, InvalidRequest, NotImplemented, ServiceFailure, InvalidToken
593
    {
594 5895 berkley
      //ObjectList ol = new ObjectList();
595
      //final SessionData sessionData = getSessionData(token);
596
      //int totalAfterQuery = 0;
597 5510 berkley
598
599 5895 berkley
      return IdentifierManager.getInstance().querySystemMetadata(startTime, endTime,
600
              objectFormat, replicaStatus, start, count);
601
602
603
      /////////////////////////////////////////////////////////////////////////
604
      ///////////////// OLD CODE //////////////////////////////////////////////
605
      /////////////////////////////////////////////////////////////////////////
606
607
//      try
608
//      {
609
//          if (PropertyService.getProperty("database.queryCacheOn").equals("true"))
610
//          {
611
//              //System.out.println("the string stored into cache is "+ resultsetBuffer.toString());
612
//              DBQuery.clearQueryResultCache();
613
//          }
614
//      }
615
//      catch (PropertyNotFoundException e1)
616
//      {
617
//          //just don't do anything
618
//      }
619
//
620
//      try
621
//      {
622
//          //TODO: Milliseconds need to be added to the dateFormat
623
//          System.out.println("=========== Listing Objects =============");
624
//          System.out.println("Current server time is: " + new Date());
625
//          if(startTime != null)
626
//          {
627
//              System.out.println("query start time is " + startTime);
628
//          }
629
//          if(endTime != null)
630
//          {
631
//              System.out.println("query end time is " + endTime);
632
//          }
633
//          params.clear();
634
//          params.put("qformat", new String[] {PropertyService.getProperty("crudService.listObjects.QFormat")});
635
//          params.put("action", new String[] {"squery"});
636
//          params.put("query", new String[] {createListObjectsPathQueryDocument()});
637
//
638
//          /*System.out.println("query is: metacatUrl: " + metacatUrl + " user: " + sessionData.getUserName() +
639
//                  " sessionid: " + sessionData.getId() + " params: ");
640
//          String url = metacatUrl + "/metacat?action=query&sessionid=" + sessionData.getId();
641
//          Enumeration keys = params.keys();
642
//          while(keys.hasMoreElements())
643
//          {
644
//              String key = (String)keys.nextElement();
645
//              String[] parr = params.get(key);
646
//              for(int i=0; i<parr.length; i++)
647
//              {
648
//                  System.out.println("param " + key + ": " + parr[i]);
649
//                  url += "&" + key + "=" + parr[i] ;
650
//              }
651
//          }
652
//          System.out.println("query url: " + url);
653
//          */
654
//          String username = "public";
655
//          String[] groups = null;
656
//          String sessionid = "";
657
//          if(sessionData != null)
658
//          {
659
//              username = sessionData.getUserName();
660
//              groups = sessionData.getGroupNames();
661
//              sessionid = sessionData.getId();
662
//          }
663
//
664
//          MetacatResultSet rs = handler.query(metacatUrl, params, username,
665
//                  groups, sessionid);
666
//          List docs = rs.getDocuments();
667
//
668
//          System.out.println("query returned " + docs.size() + " documents.");
669
//          Vector<Document> docCopy = new Vector<Document>();
670
//
671
//          //preparse the list to remove any that don't match the query params
672
//          /* TODO: this type of query/subquery processing is probably not scalable
673
//           * to larger object stores.  This code should be revisited.  The metacat
674
//           * query handler should probably be altered to handle the type of query
675
//           * done here.
676
//           */
677
//          for(int i=0; i<docs.size(); i++)
678
//          {
679
//              Document d = (Document)docs.get(i);
680
//
681
//              ObjectFormat returnedObjectFormat = ObjectFormat.convert(d.getField("objectFormat"));
682
//
683
//              if(returnedObjectFormat != null &&
684
//                 objectFormat != null &&
685
//                 !objectFormat.toString().trim().equals(returnedObjectFormat.toString().trim()))
686
//              { //make sure the objectFormat is the one specified
687
//                  continue;
688
//              }
689
//
690
//              String dateSMM = d.getField("dateSysMetadataModified");
691
//              if((startTime != null || endTime != null) && dateSMM == null)
692
//              {  //if startTime or endTime are not null, we need a date to compare to
693
//                  continue;
694
//              }
695
//
696
//              //date parse
697
//              Date dateSysMetadataModified = null;
698
//              if(dateSMM != null)
699
//              {
700
//
701
//                  /*
702
//                  if(dateSMM.indexOf(".") != -1)
703
//                  {  //strip the milliseconds
704
//                      //TODO: don't do this. we need milliseconds now.
705
//                      //TODO: explore ISO 8601 to figure out milliseconds
706
//                      dateSMM = dateSMM.substring(0, dateSMM.indexOf(".")) + 'Z';
707
//                  }
708
//                  */
709
//                  //System.out.println("dateSMM: " + dateSMM);
710
//                  //dateFormat.setTimeZone(TimeZone.getTimeZone("GMT-0"));
711
//                  try
712
//                  {   //the format we want
713
//                      dateSysMetadataModified = dateFormat.parse(dateSMM);
714
//                  }
715
//                  catch(java.text.ParseException pe)
716
//                  {   //try another legacy format
717
//                      try
718
//                      {
719
//                          DateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.S'Z'");
720
//                          dateFormat2.setTimeZone(TimeZone.getTimeZone("GMT-0"));
721
//                          dateSysMetadataModified = dateFormat2.parse(dateSMM);
722
//                      }
723
//                      catch(java.text.ParseException pe2)
724
//                      {
725
//                          //try another legacy format
726
//                          DateFormat dateFormat3 = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'");
727
//                          dateFormat3.setTimeZone(TimeZone.getTimeZone("GMT-0"));
728
//                          dateSysMetadataModified = dateFormat3.parse(dateSMM);
729
//                      }
730
//
731
//                  }
732
//              }
733
//
734
//              /*System.out.println("====================================");
735
//              System.out.println("doc number " + i);
736
//              System.out.println("docid: " + d.docid);
737
//              System.out.println("guid: " + d.getField("identifier").trim());
738
//              System.out.println("dateSMM: " + dateSMM);
739
//              System.out.println("dateSysMetadataModified: " + dateSysMetadataModified);
740
//              System.out.println("startTime: " + startTime);
741
//              System.out.println("endtime: " + endTime);*/
742
//
743
//              int startDateComparison = 0;
744
//              int endDateComparison = 0;
745
//              if(startTime != null)
746
//              {
747
//                  Calendar zTime = Calendar.getInstance(TimeZone.getTimeZone("GMT-0"));
748
//                  zTime.setTime(startTime);
749
//                  startTime = zTime.getTime();
750
//
751
//                  if(dateSysMetadataModified == null)
752
//                  {
753
//                      startDateComparison = -1;
754
//                  }
755
//                  else
756
//                  {
757
//                      startDateComparison = dateSysMetadataModified.compareTo(startTime);
758
//                  }
759
//                  //System.out.println("startDateCom: " + startDateComparison);
760
//              }
761
//              else
762
//              {
763
//                  startDateComparison = 1;
764
//              }
765
//
766
//              if(endTime != null)
767
//              {
768
//                  Calendar zTime = Calendar.getInstance(TimeZone.getTimeZone("GMT-0"));
769
//                  zTime.setTime(endTime);
770
//                  endTime = zTime.getTime();
771
//
772
//                  if(dateSysMetadataModified == null)
773
//                  {
774
//                      endDateComparison = 1;
775
//                  }
776
//                  else
777
//                  {
778
//                      endDateComparison = dateSysMetadataModified.compareTo(endTime);
779
//                  }
780
//                  //System.out.println("endDateCom: " + endDateComparison);
781
//              }
782
//              else
783
//              {
784
//                  endDateComparison = -1;
785
//              }
786
//
787
//
788
//              if(startDateComparison < 0 || endDateComparison > 0)
789
//              {
790
//                  continue;
791
//              }
792
//
793
//              docCopy.add((Document)docs.get(i));
794
//          } //end pre-parse
795
//
796
//          docs = docCopy;
797
//          totalAfterQuery = docs.size();
798
//          //System.out.println("total after subquery: " + totalAfterQuery);
799
//
800
//          //make sure we don't run over the end
801
//          int end = start + count;
802
//          if(end > docs.size())
803
//          {
804
//              end = docs.size();
805
//          }
806
//
807
//          for(int i=start; i<end; i++)
808
//          {
809
//              //get the document from the result
810
//              Document d = (Document)docs.get(i);
811
//              //System.out.println("processing doc " + d.docid);
812
//
813
//              String dateSMM = d.getField("dateSysMetadataModified");
814
//              //System.out.println("dateSMM: " + dateSMM);
815
//              //System.out.println("parsed date: " + parseDate(dateSMM));
816
//              Date dateSysMetadataModified = null;
817
//              if(dateSMM != null)
818
//              {
819
//                  try
820
//                  {
821
//                      dateSysMetadataModified = parseDate(dateSMM);
822
//                  }
823
//                  catch(Exception e)
824
//                  { //if we fail to parse the date, just ignore the value
825
//                      dateSysMetadataModified = null;
826
//                  }
827
//              }
828
//              ObjectFormat returnedObjectFormat = ObjectFormat.convert(d.getField("objectFormat"));
829
//
830
//
831
//              ObjectInfo info = new ObjectInfo();
832
//              //add the fields to the info object
833
//              Checksum cs = new Checksum();
834
//              cs.setValue(d.getField("checksum"));
835
//              String csalg = d.getField("algorithm");
836
//              if(csalg == null)
837
//              {
838
//                  csalg = "MD5";
839
//              }
840
//              ChecksumAlgorithm ca = ChecksumAlgorithm.convert(csalg);
841
//              cs.setAlgorithm(ca);
842
//              info.setChecksum(cs);
843
//              info.setDateSysMetadataModified(dateSysMetadataModified);
844
//              Identifier id = new Identifier();
845
//              id.setValue(d.getField("identifier").trim());
846
//              info.setIdentifier(id);
847
//              info.setObjectFormat(returnedObjectFormat);
848
//              String size = d.getField("size");
849
//              if(size != null)
850
//              {
851
//                  info.setSize(new Long(size.trim()).longValue());
852
//              }
853
//              //add the ObjectInfo to the ObjectList
854
//              //logCrud.info("objectFormat: " + info.getObjectFormat().toString());
855
//              //logCrud.info("id: " + info.getIdentifier().getValue());
856
//
857
//              if(info.getIdentifier().getValue() != null)
858
//              { //id can be null from tests.  should not happen in production.
859
//                  if((info.getObjectFormat() != null && !info.getObjectFormat().toString().trim().equals("")))
860
//                  { //objectFormat needs to not be null and not be an empty string
861
//                    ol.addObjectInfo(info);
862
//                  }
863
//                  else
864
//                  {
865
//                      logCrud.info("Not adding object with null objectFormat" + info.getIdentifier().getValue().toString());
866
//                  }
867
//              }
868
//
869
//          }
870
//      }
871
//      catch(Exception e)
872
//      {
873
//          e.printStackTrace();
874
//          logCrud.error("Error creating ObjectList: " + e.getMessage() + " cause: " + e.getCause());
875
//          throw new ServiceFailure("1580", "Error retrieving ObjectList: " + e.getMessage());
876
//      }
877
//      String username = "public";
878
//      if(sessionData != null)
879
//      {
880
//          username = sessionData.getUserName();
881
//      }
882
//      EventLog.getInstance().log(metacatUrl,
883
//              username, null, "read");
884
//      logCrud.info("listObjects");
885
//      if(totalAfterQuery < count)
886
//      {
887
//          count = totalAfterQuery;
888
//      }
889
//      ol.setCount(count);
890
//      ol.setStart(start);
891
//      ol.setTotal(totalAfterQuery);
892
//      return ol;
893 5359 berkley
    }
894
895
    /**
896
     * Call listObjects with the default values for replicaStatus (true), start (0),
897
     * and count (1000).
898
     * @param token
899
     * @param startTime
900
     * @param endTime
901
     * @param objectFormat
902
     * @return
903
     * @throws NotAuthorized
904
     * @throws InvalidRequest
905
     * @throws NotImplemented
906
     * @throws ServiceFailure
907
     * @throws InvalidToken
908
     */
909
    public ObjectList listObjects(AuthToken token, Date startTime, Date endTime,
910
        ObjectFormat objectFormat)
911
      throws NotAuthorized, InvalidRequest, NotImplemented, ServiceFailure, InvalidToken
912
    {
913
       return listObjects(token, startTime, endTime, objectFormat, true, 0, 1000);
914
    }
915 5298 jones
916 5359 berkley
    /**
917 5654 berkley
     * Delete a document.
918 5359 berkley
     */
919 5320 jones
    public Identifier delete(AuthToken token, Identifier guid)
920 5298 jones
            throws InvalidToken, ServiceFailure, NotAuthorized, NotFound,
921 5654 berkley
            NotImplemented, InvalidRequest {
922 5392 berkley
        logCrud.info("delete");
923 5654 berkley
924
        if(token == null || token.getToken().equals("publid"))
925
        {
926
            throw new NotAuthorized("1320", "You must be logged in to delete records.");
927
        }
928
929
        if(guid == null || guid.getValue().trim().equals(""))
930
        {
931
            throw new InvalidRequest("1322", "No GUID specified in CrudService.delete()");
932
        }
933
        final SessionData sessionData = getSessionData(token);
934
        IdentifierManager manager = IdentifierManager.getInstance();
935
936
        String docid;
937
        try
938
        {
939
            docid = manager.getLocalId(guid.getValue());
940
        }
941
        catch(McdbDocNotFoundException mnfe)
942
        {
943
            throw new InvalidRequest("1322", "GUID " + guid + " not found.");
944
        }
945
946
        try
947
        {
948
            DocumentImpl.delete(docid, sessionData.getUserName(), sessionData.getGroupNames(), null);
949
        }
950
        catch(Exception e)
951
        {
952
            throw new ServiceFailure("1350", "Could not delete document: " + e.getMessage());
953
        }
954
955
        return guid;
956 5298 jones
    }
957
958 5359 berkley
    /**
959 5648 berkley
     * describe a document.
960 5359 berkley
     */
961 5320 jones
    public DescribeResponse describe(AuthToken token, Identifier guid)
962 5298 jones
            throws InvalidToken, ServiceFailure, NotAuthorized, NotFound,
963 5648 berkley
            NotImplemented, InvalidRequest {
964 5392 berkley
        logCrud.info("describe");
965 5648 berkley
966
        if(token == null)
967
        {
968
            throw new InvalidToken("1370", "Authentication token is null");
969
        }
970
971
        if(guid == null || guid.getValue().trim().equals(""))
972
        {
973
            throw new InvalidRequest("1362", "Guid is null.  A valid guid is required.");
974
        }
975
976
        SystemMetadata sm = getSystemMetadata(token, guid);
977
        DescribeResponse dr = new DescribeResponse(sm.getObjectFormat(),
978
                sm.getSize(), sm.getDateSysMetadataModified(), sm.getChecksum());
979
        return dr;
980 5298 jones
    }
981
982 5359 berkley
    /**
983
     * get a document with a specified guid.
984
     */
985 5320 jones
    public InputStream get(AuthToken token, Identifier guid)
986 5298 jones
            throws InvalidToken, ServiceFailure, NotAuthorized, NotFound,
987
            NotImplemented {
988
989
        // Retrieve the session information from the AuthToken
990
        // If the session is expired, then the user is 'public'
991 5436 berkley
        if(token == null)
992
        {
993
            token = new AuthToken("Public");
994
        }
995 5298 jones
        final SessionData sessionData = getSessionData(token);
996
997
        // Look up the localId for this global identifier
998
        IdentifierManager im = IdentifierManager.getInstance();
999 5683 berkley
1000 5679 berkley
        try
1001
        {
1002 5320 jones
            final String localId = im.getLocalId(guid.getValue());
1003 5683 berkley
            InputStream objectStream;
1004 5679 berkley
            try
1005
            {
1006
                String username = "public";
1007
                String[] groups = new String[0];
1008
                if(sessionData != null)
1009
                {
1010
                    username = sessionData.getUserName();
1011
                    groups = sessionData.getGroupNames();
1012
                }
1013 5298 jones
1014 5683 berkley
                objectStream = readFromMetacat(localId, username, groups);
1015 5679 berkley
1016
            } catch (PropertyNotFoundException e) {
1017
                e.printStackTrace();
1018
                throw new ServiceFailure("1030", "Error getting property from metacat: " + e.getMessage());
1019
            } catch (ClassNotFoundException e) {
1020
                e.printStackTrace();
1021
                throw new ServiceFailure("1030", "Class not found error when reading from metacat: " + e.getMessage());
1022
            } catch (IOException e) {
1023
                e.printStackTrace();
1024
                throw new ServiceFailure("1030", "IOException while reading from metacat: " + e.getMessage());
1025
            } catch (SQLException e) {
1026
                e.printStackTrace();
1027
                throw new ServiceFailure("1030", "SQLException while reading from metacat: " + e.getMessage());
1028
            } catch (McdbException e) {
1029
                e.printStackTrace();
1030
                throw new ServiceFailure("1030", "Metacat DB exception while reading from metacat: " + e.getMessage());
1031
            } catch (ParseLSIDException e) {
1032
                e.printStackTrace();
1033
                throw new NotFound("1020", "LSID parsing exception while reading from metacat: " + e.getMessage());
1034
            } catch (InsufficientKarmaException e) {
1035
                e.printStackTrace();
1036
                throw new NotAuthorized("1000", "User not authorized for get(): " + e.getMessage());
1037
            }
1038
1039
1040 5431 berkley
            String username = "public";
1041
            if(sessionData != null)
1042
            {
1043
                username = sessionData.getUserName();
1044
            }
1045
1046 5383 berkley
            EventLog.getInstance().log(metacatUrl,
1047 5384 berkley
                    username, im.getLocalId(guid.getValue()), "read");
1048 5459 berkley
            logCrud.info("get D1GUID:" + guid.getValue() + ":D1SCIMETADATA:" + localId +
1049
                    ":");
1050 5680 berkley
1051 5298 jones
            return objectStream;
1052 5679 berkley
        }
1053
        catch (McdbDocNotFoundException e)
1054
        {
1055 5356 berkley
            throw new NotFound("1020", e.getMessage());
1056 5621 berkley
        }
1057 5298 jones
    }
1058
1059 5359 berkley
    /**
1060 5621 berkley
     * get the checksum for a document.  defaults to MD5.
1061 5359 berkley
     */
1062 5320 jones
    public Checksum getChecksum(AuthToken token, Identifier guid)
1063 5298 jones
            throws InvalidToken, ServiceFailure, NotAuthorized, NotFound,
1064 5621 berkley
            InvalidRequest, NotImplemented
1065
    {
1066 5392 berkley
        logCrud.info("getChecksum");
1067 5621 berkley
        return getChecksum(token, guid, "MD5");
1068 5298 jones
    }
1069
1070 5359 berkley
    /**
1071 5621 berkley
     * get the checksum for a document with the given algorithm
1072 5359 berkley
     */
1073 5320 jones
    public Checksum getChecksum(AuthToken token, Identifier guid,
1074 5298 jones
            String checksumAlgorithm) throws InvalidToken, ServiceFailure,
1075 5621 berkley
            NotAuthorized, NotFound, InvalidRequest, NotImplemented
1076
    {
1077 5392 berkley
        logCrud.info("getChecksum");
1078 5670 berkley
        SystemMetadata sm = getSystemMetadata(token, guid);
1079
        Checksum cs = sm.getChecksum();
1080
        if(cs.getAlgorithm().toString().equals(checksumAlgorithm))
1081 5644 berkley
        {
1082 5670 berkley
            return cs;
1083 5644 berkley
        }
1084 5670 berkley
        else
1085 5621 berkley
        {
1086 5670 berkley
            if(checksumAlgorithm == null)
1087
            {
1088
                checksumAlgorithm = "MD5";
1089
            }
1090
            InputStream docStream = get(token, guid);
1091
            String checksum;
1092
            try
1093
            {
1094
                checksum = checksum(docStream, checksumAlgorithm);
1095
            }
1096
            catch(Exception e)
1097
            {
1098
                throw new ServiceFailure("1410", "Error getting checksum: " + e.getMessage());
1099
            }
1100
            Checksum c = new Checksum();
1101
            c.setAlgorithm(ChecksumAlgorithm.convert(checksumAlgorithm));
1102
            c.setValue(checksum);
1103
            return c;
1104 5621 berkley
        }
1105 5298 jones
    }
1106
1107 5359 berkley
    /**
1108 5384 berkley
     * get log records.
1109 5359 berkley
     */
1110 5390 berkley
    public Log getLogRecords(AuthToken token, Date fromDate, Date toDate, Event event)
1111 5298 jones
            throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest,
1112 5384 berkley
            NotImplemented
1113
    {
1114 5630 berkley
        /*System.out.println("=================== Getting log records ===================");
1115 5430 berkley
        System.out.println("Current server time is: " + new Date());
1116
        if(fromDate != null)
1117
        {
1118
          System.out.println("query start time is " + fromDate);
1119
        }
1120
        if(toDate != null)
1121
        {
1122
          System.out.println("query end time is " + toDate);
1123 5630 berkley
        }*/
1124 5389 berkley
        Log log = new Log();
1125
        Vector<LogEntry> logs = new Vector<LogEntry>();
1126 5384 berkley
        IdentifierManager im = IdentifierManager.getInstance();
1127
        EventLog el = EventLog.getInstance();
1128 5391 berkley
        if(fromDate == null)
1129
        {
1130 5630 berkley
            //System.out.println("setting fromdate from null");
1131 5391 berkley
            fromDate = new Date(1);
1132
        }
1133
        if(toDate == null)
1134
        {
1135 5630 berkley
            //System.out.println("setting todate from null");
1136 5391 berkley
            toDate = new Date();
1137
        }
1138 5418 berkley
1139 5630 berkley
        //System.out.println("fromDate: " + fromDate);
1140
        //System.out.println("toDate: " + toDate);
1141 5418 berkley
1142 5384 berkley
        String report = el.getReport(null, null, null, null,
1143
                new java.sql.Timestamp(fromDate.getTime()),
1144 5693 leinfelder
                new java.sql.Timestamp(toDate.getTime()), false);
1145 5384 berkley
1146 5418 berkley
        //System.out.println("report: " + report);
1147
1148 5384 berkley
        String logEntry = "<logEntry>";
1149
        String endLogEntry = "</logEntry>";
1150
        int startIndex = 0;
1151
        int foundIndex = report.indexOf(logEntry, startIndex);
1152
        while(foundIndex != -1)
1153
        {
1154
            //parse out each entry
1155
            int endEntryIndex = report.indexOf(endLogEntry, foundIndex);
1156
            String entry = report.substring(foundIndex, endEntryIndex);
1157
            //System.out.println("entry: " + entry);
1158
            startIndex = endEntryIndex + endLogEntry.length();
1159
            foundIndex = report.indexOf(logEntry, startIndex);
1160
1161
            String entryId = getLogEntryField("entryid", entry);
1162
            String ipAddress = getLogEntryField("ipAddress", entry);
1163
            String principal = getLogEntryField("principal", entry);
1164
            String docid = getLogEntryField("docid", entry);
1165 5390 berkley
            String eventS = getLogEntryField("event", entry);
1166 5384 berkley
            String dateLogged = getLogEntryField("dateLogged", entry);
1167
1168 5389 berkley
            LogEntry le = new LogEntry();
1169 5384 berkley
1170 5390 berkley
            Event e = Event.convert(eventS);
1171 5384 berkley
            if(e == null)
1172
            { //skip any events that are not Dataone Crud events
1173
                continue;
1174
            }
1175 5389 berkley
            le.setEvent(e);
1176 5384 berkley
            Identifier entryid = new Identifier();
1177
            entryid.setValue(entryId);
1178 5389 berkley
            le.setEntryId(entryid);
1179 5384 berkley
            Identifier identifier = new Identifier();
1180
            try
1181
            {
1182 5432 berkley
                //System.out.println("converting docid '" + docid + "' to a guid.");
1183 5417 berkley
                if(docid == null || docid.trim().equals("") || docid.trim().equals("null"))
1184
                {
1185
                    continue;
1186
                }
1187 5416 berkley
                docid = docid.substring(0, docid.lastIndexOf("."));
1188 5384 berkley
                identifier.setValue(im.getGUID(docid, im.getLatestRevForLocalId(docid)));
1189
            }
1190
            catch(Exception ex)
1191
            { //try to get the guid, if that doesn't work, just use the local id
1192 5419 berkley
                //throw new ServiceFailure("1030", "Error getting guid for localId " +
1193 5424 berkley
                //        docid + ": " + ex.getMessage());\
1194
1195
                //skip it if the guid can't be found
1196 5419 berkley
                continue;
1197 5384 berkley
            }
1198
1199 5389 berkley
            le.setIdentifier(identifier);
1200
            le.setIpAddress(ipAddress);
1201 5384 berkley
            Calendar c = Calendar.getInstance();
1202
            String year = dateLogged.substring(0, 4);
1203
            String month = dateLogged.substring(5, 7);
1204
            String date = dateLogged.substring(8, 10);
1205
            //System.out.println("year: " + year + " month: " + month + " day: " + date);
1206
            c.set(new Integer(year).intValue(), new Integer(month).intValue(), new Integer(date).intValue());
1207
            Date logDate = c.getTime();
1208 5389 berkley
            le.setDateLogged(logDate);
1209 5384 berkley
            NodeReference memberNode = new NodeReference();
1210
            memberNode.setValue(ipAddress);
1211 5389 berkley
            le.setMemberNode(memberNode);
1212 5384 berkley
            Principal princ = new Principal();
1213
            princ.setValue(principal);
1214 5389 berkley
            le.setPrincipal(princ);
1215
            le.setUserAgent("metacat/RESTService");
1216 5390 berkley
1217
            if(event == null)
1218
            {
1219
                logs.add(le);
1220
            }
1221
1222
            if(event != null &&
1223
               e.toString().toLowerCase().trim().equals(event.toString().toLowerCase().trim()))
1224
            {
1225
              logs.add(le);
1226
            }
1227 5384 berkley
        }
1228
1229 5389 berkley
        log.setLogEntryList(logs);
1230 5392 berkley
        logCrud.info("getLogRecords");
1231 5389 berkley
        return log;
1232 5298 jones
    }
1233 5384 berkley
1234
    /**
1235
     * parse a logEntry and get the relavent field from it
1236
     * @param fieldname
1237
     * @param entry
1238
     * @return
1239
     */
1240
    private String getLogEntryField(String fieldname, String entry)
1241
    {
1242
        String begin = "<" + fieldname + ">";
1243
        String end = "</" + fieldname + ">";
1244
        //System.out.println("looking for " + begin + " and " + end + " in entry " + entry);
1245
        String s = entry.substring(entry.indexOf(begin) + begin.length(), entry.indexOf(end));
1246
        //System.out.println("entry " + fieldname + " : " + s);
1247
        return s;
1248
    }
1249 5298 jones
1250 5359 berkley
    /**
1251
     * get the system metadata for a document with a specified guid.
1252
     */
1253 5481 berkley
public SystemMetadata getSystemMetadata(AuthToken token, Identifier guid)
1254 5298 jones
            throws InvalidToken, ServiceFailure, NotAuthorized, NotFound,
1255
            InvalidRequest, NotImplemented {
1256 5319 jones
1257 5332 jones
        logMetacat.debug("CrudService.getSystemMetadata - for guid: " + guid.getValue());
1258
1259
        // Retrieve the session information from the AuthToken
1260
        // If the session is expired, then the user is 'public'
1261
        final SessionData sessionData = getSessionData(token);
1262
1263
        try {
1264
            IdentifierManager im = IdentifierManager.getInstance();
1265 5424 berkley
            final String localId = im.getSystemMetadataLocalId(guid.getValue());
1266 5683 berkley
            InputStream objectStream;
1267 5332 jones
1268 5683 berkley
            try {
1269
                String username = "public";
1270
                String[] groupnames = null;
1271
                if(sessionData != null)
1272
                {
1273
                    username = sessionData.getUserName();
1274
                    groupnames = sessionData.getGroupNames();
1275
                }
1276 5332 jones
1277 5683 berkley
                objectStream = readFromMetacat(localId, username, groupnames);
1278
1279
            } catch (PropertyNotFoundException e) {
1280
                e.printStackTrace();
1281
                throw new ServiceFailure("1090", "Property not found while reading system metadata from metacat: " + e.getMessage());
1282
            } catch (ClassNotFoundException e) {
1283
                e.printStackTrace();
1284
                throw new ServiceFailure("1090", "Class not found while reading system metadata from metacat: " + e.getMessage());
1285
            } catch (IOException e) {
1286
                e.printStackTrace();
1287
                throw new ServiceFailure("1090", "IOException while reading system metadata from metacat: " + e.getMessage());
1288
            } catch (SQLException e) {
1289
                e.printStackTrace();
1290
                throw new ServiceFailure("1090", "SQLException while reading system metadata from metacat: " + e.getMessage());
1291
            } catch (McdbException e) {
1292
                e.printStackTrace();
1293
                throw new ServiceFailure("1090", "Metacat DB Exception while reading system metadata from metacat: " + e.getMessage());
1294
            } catch (ParseLSIDException e) {
1295
                e.printStackTrace();
1296
                throw new NotFound("1060", "Error parsing LSID while reading system metadata from metacat: " + e.getMessage());
1297
            } catch (InsufficientKarmaException e) {
1298
                e.printStackTrace();
1299
                throw new NotAuthorized("1040", "User not authorized for get() on system metadata: " + e.getMessage());
1300
            }
1301 5449 berkley
1302 5332 jones
            // Deserialize the xml to create a SystemMetadata object
1303
            SystemMetadata sysmeta = deserializeSystemMetadata(objectStream);
1304 5431 berkley
            String username = "public";
1305
            if(sessionData != null)
1306
            {
1307
                username = sessionData.getUserName();
1308
            }
1309 5383 berkley
            EventLog.getInstance().log(metacatUrl,
1310 5384 berkley
                    username, im.getLocalId(guid.getValue()), "read");
1311 5459 berkley
            logCrud.info("getsystemmetadata D1GUID:" + guid.getValue()  +
1312 5582 berkley
                    ":D1SYSMETADATA:"+ localId + ":");
1313 5332 jones
            return sysmeta;
1314
1315
        } catch (McdbDocNotFoundException e) {
1316 5348 berkley
            //e.printStackTrace();
1317 5624 berkley
            throw new NotFound("1040", e.getMessage());
1318 5332 jones
        }
1319 5298 jones
    }
1320 5366 berkley
1321
    /**
1322
     * parse the date in the systemMetadata
1323
     * @param s
1324
     * @return
1325
     * @throws Exception
1326
     */
1327 5418 berkley
    public Date parseDate(String s)
1328 5366 berkley
      throws Exception
1329
    {
1330 5466 berkley
        /* TODO:
1331
         * This method should be replaced by a DateFormatter
1332
         */
1333 5366 berkley
        Date d = null;
1334
        int tIndex = s.indexOf("T");
1335
        int zIndex = s.indexOf("Z");
1336
        if(tIndex != -1 && zIndex != -1)
1337
        { //parse a date that looks like 2010-05-18T21:12:54.362Z
1338
            //System.out.println("original date: " + s);
1339
1340
            String date = s.substring(0, tIndex);
1341
            String year = date.substring(0, date.indexOf("-"));
1342
            String month = date.substring(date.indexOf("-") + 1, date.lastIndexOf("-"));
1343
            String day = date.substring(date.lastIndexOf("-") + 1, date.length());
1344
            /*System.out.println("date: " + "year: " + new Integer(year).intValue() +
1345
                    " month: " + new Integer(month).intValue() + " day: " +
1346
                    new Integer(day).intValue());
1347
            */
1348
            String time = s.substring(tIndex + 1, zIndex);
1349
            String hour = time.substring(0, time.indexOf(":"));
1350
            String minute = time.substring(time.indexOf(":") + 1, time.lastIndexOf(":"));
1351
            String seconds = "00";
1352
            String milliseconds = "00";
1353
            if(time.indexOf(".") != -1)
1354
            {
1355
                seconds = time.substring(time.lastIndexOf(":") + 1, time.indexOf("."));
1356
                milliseconds = time.substring(time.indexOf(".") + 1, time.length());
1357
            }
1358 5418 berkley
            else
1359
            {
1360
                seconds = time.substring(time.lastIndexOf(":") + 1, time.length());
1361
            }
1362 5366 berkley
            /*System.out.println("time: " + "hour: " + new Integer(hour).intValue() +
1363
                    " minute: " + new Integer(minute).intValue() + " seconds: " +
1364
                    new Integer(seconds).intValue() + " milli: " +
1365
                    new Integer(milliseconds).intValue());*/
1366
1367
            //d = DateFormat.getDateTimeInstance().parse(date + " " + time);
1368 5630 berkley
            Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT-0")/*TimeZone.getDefault()*/);
1369 5366 berkley
            c.set(new Integer(year).intValue(), new Integer(month).intValue() - 1,
1370
                  new Integer(day).intValue(), new Integer(hour).intValue(),
1371
                  new Integer(minute).intValue(), new Integer(seconds).intValue());
1372
            c.set(Calendar.MILLISECOND, new Integer(milliseconds).intValue());
1373
            d = new Date(c.getTimeInMillis());
1374
            //System.out.println("d: " + d);
1375
            return d;
1376
        }
1377
        else
1378
        {  //if it's not in the expected format, try the formatter
1379
            return DateFormat.getDateTimeInstance().parse(s);
1380
        }
1381
    }
1382 5298 jones
1383 5331 jones
    /*
1384
     * Look up the information on the session using the token provided in
1385
     * the AuthToken.  The Session should have all relevant user information.
1386
     * If the session has expired or is invalid, the 'public' session will
1387
     * be returned, giving the user anonymous access.
1388
     */
1389 5394 berkley
    public static SessionData getSessionData(AuthToken token) {
1390 5331 jones
        SessionData sessionData = null;
1391
        String sessionId = "PUBLIC";
1392
        if (token != null) {
1393
            sessionId = token.getToken();
1394
        }
1395
1396
        // if the session id is registered in SessionService, get the
1397
        // SessionData for it. Otherwise, use the public session.
1398 5411 berkley
        //System.out.println("sessionid: " + sessionId);
1399 5403 berkley
        if (sessionId != null &&
1400 5406 berkley
            !sessionId.toLowerCase().equals("public") &&
1401 5403 berkley
            SessionService.getInstance().isSessionRegistered(sessionId))
1402
        {
1403 5374 berkley
            sessionData = SessionService.getInstance().getRegisteredSession(sessionId);
1404 5331 jones
        } else {
1405 5374 berkley
            sessionData = SessionService.getInstance().getPublicSession();
1406 5331 jones
        }
1407 5411 berkley
1408 5331 jones
        return sessionData;
1409
    }
1410
1411
    /**
1412
     * Determine if a given object should be treated as an XML science metadata
1413
     * object.
1414
     *
1415
     * TODO: This test should be externalized in a configuration dictionary rather than being hardcoded.
1416
     *
1417
     * @param sysmeta the SystemMetadata describig the object
1418
     * @return true if the object should be treated as science metadata
1419
     */
1420
    private boolean isScienceMetadata(SystemMetadata sysmeta) {
1421 5523 berkley
        /*boolean scimeta = false;
1422 5466 berkley
        //TODO: this should be read from a .properties file instead of being hard coded
1423 5331 jones
        switch (sysmeta.getObjectFormat()) {
1424
            case EML_2_1_0: scimeta = true; break;
1425
            case EML_2_0_1: scimeta = true; break;
1426
            case EML_2_0_0: scimeta = true; break;
1427
            case FGDC_STD_001_1_1999: scimeta = true; break;
1428
            case FGDC_STD_001_1998: scimeta = true; break;
1429
            case NCML_2_2: scimeta = true; break;
1430 5521 berkley
            case DSPACE_METS_SIP_1_0: scimeta = true; break;
1431 5331 jones
        }
1432
1433 5523 berkley
        return scimeta;*/
1434
1435
        return MetadataTypeRegister.isMetadataType(sysmeta.getObjectFormat());
1436 5331 jones
    }
1437
1438 5359 berkley
    /**
1439
     * insert a data doc
1440
     * @param object
1441
     * @param guid
1442
     * @param sessionData
1443
     * @throws ServiceFailure
1444 5459 berkley
     * @returns localId of the data object inserted
1445 5359 berkley
     */
1446 5459 berkley
    private String insertDataObject(InputStream object, Identifier guid,
1447 5331 jones
            SessionData sessionData) throws ServiceFailure {
1448
1449 5431 berkley
        String username = "public";
1450
        String[] groups = null;
1451
        if(sessionData != null)
1452
        {
1453
          username = sessionData.getUserName();
1454
          groups = sessionData.getGroupNames();
1455
        }
1456 5331 jones
1457
        // generate guid/localId pair for object
1458
        logMetacat.debug("Generating a guid/localId mapping");
1459
        IdentifierManager im = IdentifierManager.getInstance();
1460
        String localId = im.generateLocalId(guid.getValue(), 1);
1461
1462
        try {
1463
            logMetacat.debug("Case DATA: starting to write to disk.");
1464
            if (DocumentImpl.getDataFileLockGrant(localId)) {
1465
1466
                // Save the data file to disk using "localId" as the name
1467
                try {
1468
                    String datafilepath = PropertyService.getProperty("application.datafilepath");
1469
1470
                    File dataDirectory = new File(datafilepath);
1471
                    dataDirectory.mkdirs();
1472
1473
                    File newFile = writeStreamToFile(dataDirectory, localId, object);
1474
1475
                    // TODO: Check that the file size matches SystemMetadata
1476
                    //                        long size = newFile.length();
1477
                    //                        if (size == 0) {
1478
                    //                            throw new IOException("Uploaded file is 0 bytes!");
1479
                    //                        }
1480
1481
                    // Register the file in the database (which generates an exception
1482
                    // if the localId is not acceptable or other untoward things happen
1483
                    try {
1484
                        logMetacat.debug("Registering document...");
1485
                        DocumentImpl.registerDocument(localId, "BIN", localId,
1486
                                username, groups);
1487
                        logMetacat.debug("Registration step completed.");
1488
                    } catch (SQLException e) {
1489
                        //newFile.delete();
1490
                        logMetacat.debug("SQLE: " + e.getMessage());
1491
                        e.printStackTrace(System.out);
1492 5356 berkley
                        throw new ServiceFailure("1190", "Registration failed: " + e.getMessage());
1493 5331 jones
                    } catch (AccessionNumberException e) {
1494
                        //newFile.delete();
1495
                        logMetacat.debug("ANE: " + e.getMessage());
1496
                        e.printStackTrace(System.out);
1497 5356 berkley
                        throw new ServiceFailure("1190", "Registration failed: " + e.getMessage());
1498 5331 jones
                    } catch (Exception e) {
1499
                        //newFile.delete();
1500
                        logMetacat.debug("Exception: " + e.getMessage());
1501
                        e.printStackTrace(System.out);
1502 5356 berkley
                        throw new ServiceFailure("1190", "Registration failed: " + e.getMessage());
1503 5331 jones
                    }
1504
1505
                    logMetacat.debug("Logging the creation event.");
1506 5344 berkley
                    EventLog.getInstance().log(metacatUrl,
1507 5384 berkley
                            username, localId, "create");
1508 5331 jones
1509
                    // Schedule replication for this data file
1510
                    logMetacat.debug("Scheduling replication.");
1511
                    ForceReplicationHandler frh = new ForceReplicationHandler(
1512 5384 berkley
                            localId, "create", false, null);
1513 5331 jones
1514
                } catch (PropertyNotFoundException e) {
1515 5356 berkley
                    throw new ServiceFailure("1190", "Could not lock file for writing:" + e.getMessage());
1516 5331 jones
                }
1517
            }
1518 5459 berkley
            return localId;
1519 5331 jones
        } catch (Exception e) {
1520
            // Could not get a lock on the document, so we can not update the file now
1521 5356 berkley
            throw new ServiceFailure("1190", "Failed to lock file: " + e.getMessage());
1522 5331 jones
        }
1523
    }
1524
1525 5359 berkley
    /**
1526
     * write a file to a stream
1527
     * @param dir
1528
     * @param fileName
1529
     * @param data
1530
     * @return
1531
     * @throws ServiceFailure
1532
     */
1533 5319 jones
    private File writeStreamToFile(File dir, String fileName, InputStream data)
1534
        throws ServiceFailure {
1535
1536
        File newFile = new File(dir, fileName);
1537
        logMetacat.debug("Filename for write is: " + newFile.getAbsolutePath());
1538
1539
        try {
1540
            if (newFile.createNewFile()) {
1541
                // write data stream to desired file
1542
                OutputStream os = new FileOutputStream(newFile);
1543
                long length = IOUtils.copyLarge(data, os);
1544
                os.flush();
1545
                os.close();
1546
            } else {
1547
                logMetacat.debug("File creation failed, or file already exists.");
1548 5356 berkley
                throw new ServiceFailure("1190", "File already exists: " + fileName);
1549 5319 jones
            }
1550
        } catch (FileNotFoundException e) {
1551
            logMetacat.debug("FNF: " + e.getMessage());
1552 5356 berkley
            throw new ServiceFailure("1190", "File not found: " + fileName + " "
1553 5319 jones
                    + e.getMessage());
1554
        } catch (IOException e) {
1555
            logMetacat.debug("IOE: " + e.getMessage());
1556 5356 berkley
            throw new ServiceFailure("1190", "File was not written: " + fileName
1557 5319 jones
                    + " " + e.getMessage());
1558
        }
1559
1560
        return newFile;
1561 5329 jones
    }
1562
1563 5350 berkley
    /**
1564 5441 berkley
     * insert a systemMetadata doc, return the localId of the sysmeta
1565 5350 berkley
     */
1566 5441 berkley
    private String insertSystemMetadata(SystemMetadata sysmeta, SessionData sessionData)
1567 5377 berkley
        throws ServiceFailure
1568
    {
1569 5329 jones
        logMetacat.debug("Starting to insert SystemMetadata...");
1570
1571
        // generate guid/localId pair for sysmeta
1572 5331 jones
        Identifier sysMetaGuid = new Identifier();
1573
        sysMetaGuid.setValue(DocumentUtil.generateDocumentId(1));
1574 5329 jones
        sysmeta.setDateSysMetadataModified(new Date());
1575 5453 berkley
        System.out.println("****inserting new system metadata with modified date " +
1576
                sysmeta.getDateSysMetadataModified());
1577 5329 jones
1578
        String xml = new String(serializeSystemMetadata(sysmeta).toByteArray());
1579 5444 berkley
        System.out.println("sysmeta: " + xml);
1580 5453 berkley
        String localId = insertDocument(xml, sysMetaGuid, sessionData, true);
1581 5420 berkley
        System.out.println("sysmeta inserted with localId " + localId);
1582 5453 berkley
        //insert the system metadata doc id into the systemmetadata table to
1583 5333 berkley
        //link it to the data or metadata document
1584 5377 berkley
        IdentifierManager.getInstance().createSystemMetadataMapping(
1585 5887 berkley
                sysmeta, sysMetaGuid.getValue());
1586 5441 berkley
        return localId;
1587 5329 jones
    }
1588
1589 5333 berkley
    /**
1590 5350 berkley
     * update a systemMetadata doc
1591
     */
1592
    private void updateSystemMetadata(SystemMetadata sm, SessionData sessionData)
1593
      throws ServiceFailure
1594
    {
1595
        try
1596
        {
1597 5424 berkley
            String smId = IdentifierManager.getInstance().getSystemMetadataLocalId(sm.getIdentifier().getValue());
1598 5630 berkley
            System.out.println("setting date modified to " + new Date());
1599 5350 berkley
            sm.setDateSysMetadataModified(new Date());
1600
            String xml = new String(serializeSystemMetadata(sm).toByteArray());
1601 5456 berkley
            String localId = updateDocument(xml, sm.getIdentifier(), null, sessionData, true);
1602 5350 berkley
            IdentifierManager.getInstance().updateSystemMetadataMapping(sm.getIdentifier().getValue(), localId);
1603
        }
1604
        catch(Exception e)
1605
        {
1606 5356 berkley
            throw new ServiceFailure("1030", "Error updating system metadata: " + e.getMessage());
1607 5350 berkley
        }
1608
    }
1609
1610 5453 berkley
    private String insertDocument(String xml, Identifier guid, SessionData sessionData)
1611
        throws ServiceFailure
1612
    {
1613
        return insertDocument(xml, guid, sessionData, false);
1614
    }
1615
1616 5350 berkley
    /**
1617
     * insert a document
1618
     * NOTE: this method shouldn't be used from the update or create() methods.
1619
     * we shouldn't be putting the science metadata or data objects into memory.
1620
     */
1621 5453 berkley
    private String insertDocument(String xml, Identifier guid, SessionData sessionData,
1622
            boolean isSystemMetadata)
1623 5350 berkley
        throws ServiceFailure
1624
    {
1625 5453 berkley
        return insertOrUpdateDocument(xml, guid, sessionData, "insert", isSystemMetadata);
1626 5350 berkley
    }
1627
1628
    /**
1629
     * insert a document from a stream
1630
     */
1631
    private String insertDocument(InputStream is, Identifier guid, SessionData sessionData)
1632
      throws IOException, ServiceFailure
1633
    {
1634
        //HACK: change this eventually.  we should not be converting the stream to a string
1635
        String xml = IOUtils.toString(is);
1636
        return insertDocument(xml, guid, sessionData);
1637
    }
1638
1639
    /**
1640
     * update a document
1641
     * NOTE: this method shouldn't be used from the update or create() methods.
1642
     * we shouldn't be putting the science metadata or data objects into memory.
1643
     */
1644 5453 berkley
    private String updateDocument(String xml, Identifier obsoleteGuid,
1645
            Identifier guid, SessionData sessionData, boolean isSystemMetadata)
1646 5350 berkley
        throws ServiceFailure
1647
    {
1648 5453 berkley
        return insertOrUpdateDocument(xml, obsoleteGuid, sessionData, "update", isSystemMetadata);
1649 5350 berkley
    }
1650
1651
    /**
1652
     * update a document from a stream
1653
     */
1654 5453 berkley
    private String updateDocument(InputStream is, Identifier obsoleteGuid,
1655
            Identifier guid, SessionData sessionData, boolean isSystemMetadata)
1656 5350 berkley
      throws IOException, ServiceFailure
1657
    {
1658
        //HACK: change this eventually.  we should not be converting the stream to a string
1659
        String xml = IOUtils.toString(is);
1660 5453 berkley
        String localId = updateDocument(xml, obsoleteGuid, guid, sessionData, isSystemMetadata);
1661 5350 berkley
        IdentifierManager im = IdentifierManager.getInstance();
1662
        if(guid != null)
1663
        {
1664
          im.createMapping(guid.getValue(), localId);
1665
        }
1666
        return localId;
1667
    }
1668
1669
    /**
1670 5333 berkley
     * insert a document, return the id of the document that was inserted
1671
     */
1672 5453 berkley
    protected String insertOrUpdateDocument(String xml, Identifier guid,
1673
            SessionData sessionData, String insertOrUpdate, boolean isSystemMetadata)
1674 5329 jones
        throws ServiceFailure {
1675
        logMetacat.debug("Starting to insert xml document...");
1676
        IdentifierManager im = IdentifierManager.getInstance();
1677
1678
        // generate guid/localId pair for sysmeta
1679 5350 berkley
        String localId = null;
1680
        if(insertOrUpdate.equals("insert"))
1681
        {
1682 5453 berkley
            localId = im.generateLocalId(guid.getValue(), 1, isSystemMetadata);
1683 5350 berkley
        }
1684
        else
1685
        {
1686
            //localid should already exist in the identifier table, so just find it
1687
            try
1688
            {
1689 5456 berkley
                System.out.println("updating guid " + guid.getValue());
1690
                if(!isSystemMetadata)
1691
                {
1692
                    System.out.println("looking in identifier table for guid " + guid.getValue());
1693
                    localId = im.getLocalId(guid.getValue());
1694
                }
1695
                else
1696
                {
1697
                    System.out.println("looking in systemmetadata table for guid " + guid.getValue());
1698
                    localId = im.getSystemMetadataLocalId(guid.getValue());
1699
                }
1700
                System.out.println("localId: " + localId);
1701 5350 berkley
                //increment the revision
1702
                String docid = localId.substring(0, localId.lastIndexOf("."));
1703
                String revS = localId.substring(localId.lastIndexOf(".") + 1, localId.length());
1704
                int rev = new Integer(revS).intValue();
1705
                rev++;
1706
                docid = docid + "." + rev;
1707
                localId = docid;
1708 5456 berkley
                System.out.println("incremented localId: " + localId);
1709 5350 berkley
            }
1710
            catch(McdbDocNotFoundException e)
1711
            {
1712 5356 berkley
                throw new ServiceFailure("1030", "CrudService.insertOrUpdateDocument(): " +
1713 5350 berkley
                    "guid " + guid.getValue() + " should have been in the identifier table, but it wasn't: " + e.getMessage());
1714
            }
1715
        }
1716 5331 jones
        logMetacat.debug("Metadata guid|localId: " + guid.getValue() + "|" +
1717 5329 jones
                localId);
1718
1719
        String[] action = new String[1];
1720 5350 berkley
        action[0] = insertOrUpdate;
1721 5329 jones
        params.put("action", action);
1722
        String[] docid = new String[1];
1723
        docid[0] = localId;
1724
        params.put("docid", docid);
1725
        String[] doctext = new String[1];
1726
        doctext[0] = xml;
1727
        logMetacat.debug(doctext[0]);
1728
        params.put("doctext", doctext);
1729 5331 jones
1730
        // TODO: refactor handleInsertOrUpdateAction() to not output XML directly
1731
        // onto output stream, or alternatively, capture that and parse it to
1732
        // generate the right exceptions
1733 5337 berkley
        //ByteArrayOutputStream output = new ByteArrayOutputStream();
1734
        //PrintWriter pw = new PrintWriter(output);
1735 5449 berkley
        String username = "public";
1736
        String[] groupnames = null;
1737
        if(sessionData != null)
1738
        {
1739
            username = sessionData.getUserName();
1740
            groupnames = sessionData.getGroupNames();
1741
        }
1742 5344 berkley
        String result = handler.handleInsertOrUpdateAction(metacatUrl, null,
1743 5449 berkley
                            null, params, username, groupnames);
1744 5461 berkley
        if(result.indexOf("<error>") != -1)
1745
        {
1746
            throw new ServiceFailure("1000", "Error inserting or updating document: " + result);
1747
        }
1748 5337 berkley
        //String outputS = new String(output.toByteArray());
1749
        logMetacat.debug("CrudService.insertDocument - Metacat returned: " + result);
1750 5333 berkley
        logMetacat.debug("Finsished inserting xml document with id " + localId);
1751
        return localId;
1752 5329 jones
    }
1753
1754 5359 berkley
    /**
1755 5555 berkley
     * serialize a dataone type
1756 5550 berkley
     */
1757 5921 jones
//    private void serializeServiceType(Class type, Object object, OutputStream out)
1758
//        throws JiBXException
1759
//    {
1760
//        IBindingFactory bfact = BindingDirectory.getFactory(type);
1761
//        IMarshallingContext mctx = bfact.createMarshallingContext();
1762
//        mctx.marshalDocument(object, "UTF-8", null, out);
1763
//    }
1764 5550 berkley
1765
    /**
1766 5359 berkley
     * serialize a system metadata doc
1767
     * @param sysmeta
1768
     * @return
1769
     * @throws ServiceFailure
1770
     */
1771 5332 jones
    public static ByteArrayOutputStream serializeSystemMetadata(SystemMetadata sysmeta)
1772 5329 jones
        throws ServiceFailure {
1773
        IBindingFactory bfact;
1774
        ByteArrayOutputStream sysmetaOut = null;
1775
        try {
1776
            bfact = BindingDirectory.getFactory(SystemMetadata.class);
1777
            IMarshallingContext mctx = bfact.createMarshallingContext();
1778
            sysmetaOut = new ByteArrayOutputStream();
1779
            mctx.marshalDocument(sysmeta, "UTF-8", null, sysmetaOut);
1780
        } catch (JiBXException e) {
1781 5382 berkley
            e.printStackTrace();
1782 5356 berkley
            throw new ServiceFailure("1190", "Failed to serialize and insert SystemMetadata: " + e.getMessage());
1783 5329 jones
        }
1784
1785
        return sysmetaOut;
1786
    }
1787 5332 jones
1788 5359 berkley
    /**
1789
     * deserialize a system metadata doc
1790
     * @param xml
1791
     * @return
1792
     * @throws ServiceFailure
1793
     */
1794 5332 jones
    public static SystemMetadata deserializeSystemMetadata(InputStream xml)
1795
        throws ServiceFailure {
1796
        try {
1797
            IBindingFactory bfact = BindingDirectory.getFactory(SystemMetadata.class);
1798
            IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
1799
            SystemMetadata sysmeta = (SystemMetadata) uctx.unmarshalDocument(xml, null);
1800
            return sysmeta;
1801
        } catch (JiBXException e) {
1802 5382 berkley
            e.printStackTrace();
1803
            throw new ServiceFailure("1190", "Failed to deserialize and insert SystemMetadata: " + e.getMessage());
1804 5332 jones
        }
1805
    }
1806 5378 berkley
1807
    /**
1808 5683 berkley
     * read a document from metacat and return the InputStream
1809
     *
1810
     * @param localId
1811
     * @param username
1812
     * @param groups
1813
     * @return
1814
     * @throws InsufficientKarmaException
1815
     * @throws ParseLSIDException
1816
     * @throws PropertyNotFoundException
1817
     * @throws McdbException
1818
     * @throws SQLException
1819
     * @throws ClassNotFoundException
1820
     * @throws IOException
1821
     */
1822
    private InputStream readFromMetacat(String localId, String username, String[] groups)
1823
        throws InsufficientKarmaException, ParseLSIDException,
1824
        PropertyNotFoundException, McdbException, SQLException,
1825
        ClassNotFoundException, IOException
1826
    {
1827
        File tmpDir;
1828
        try
1829
        {
1830
            tmpDir = new File(PropertyService.getProperty("application.tempDir"));
1831
        }
1832
        catch(PropertyNotFoundException pnfe)
1833
        {
1834
            logMetacat.error("ResourceHandler.writeMMPPartstoFiles: " +
1835
                    "application.tmpDir not found.  Using /tmp instead.");
1836
            tmpDir = new File("/tmp");
1837
        }
1838
        Date d = new Date();
1839
        final File outputFile = new File(tmpDir, "metacat.output." + d.getTime());
1840
        FileOutputStream dataSink = new FileOutputStream(outputFile);
1841
1842
        handler.readFromMetacat(metacatUrl, null,
1843
                dataSink, localId, "xml",
1844
                username,
1845
                groups, true, params);
1846
1847
        //set a timer to clean up the temp files
1848
        Timer t = new Timer();
1849
        TimerTask tt = new TimerTask() {
1850
            @Override
1851
            public void run()
1852
            {
1853
                outputFile.delete();
1854
            }
1855
        };
1856
        t.schedule(tt, 20000); //schedule after 20 secs
1857
1858
        InputStream objectStream = new FileInputStream(outputFile);
1859
        return objectStream;
1860
    }
1861
1862
    /**
1863 5621 berkley
     * return an MD5 checksum for the stream
1864
     * @param is
1865
     * @return
1866 5920 jones
     * @throws IOException
1867
     * @throws NoSuchAlgorithmException
1868 5378 berkley
     */
1869 5920 jones
    public static String checksum(InputStream is) throws NoSuchAlgorithmException, IOException
1870 5621 berkley
    {
1871
        return checksum(is, "MD5");
1872
    }
1873
1874
    /**
1875
     * produce a checksum for item using the given algorithm
1876 5920 jones
     * @throws IOException
1877
     * @throws NoSuchAlgorithmException
1878 5621 berkley
     */
1879 5920 jones
    public static String checksum(InputStream is, String algorithm) throws NoSuchAlgorithmException, IOException
1880 5378 berkley
    {
1881 5851 berkley
        return ServiceTypeUtil.checksum(is, ChecksumAlgorithm.convert(algorithm)).getValue();
1882 5378 berkley
    }
1883
1884
    /**
1885
     * parse the metacat date which looks like 2010-06-08 (YYYY-MM-DD) into
1886
     * a proper date object
1887
     * @param date
1888
     * @return
1889
     */
1890
    private Date parseMetacatDate(String date)
1891
    {
1892
        String year = date.substring(0, 4);
1893
        String month = date.substring(5, 7);
1894
        String day = date.substring(8, 10);
1895 5420 berkley
        Calendar c = Calendar.getInstance(TimeZone.getDefault());
1896 5378 berkley
        c.set(new Integer(year).intValue(),
1897
              new Integer(month).intValue(),
1898
              new Integer(day).intValue());
1899 5420 berkley
        System.out.println("time in parseMetacatDate: " + c.getTime());
1900 5378 berkley
        return c.getTime();
1901
    }
1902
1903
    /**
1904
     * find the size (in bytes) of a stream
1905
     * @param is
1906
     * @return
1907
     * @throws IOException
1908
     */
1909
    private long sizeOfStream(InputStream is)
1910
        throws IOException
1911
    {
1912
        long size = 0;
1913
        byte[] b = new byte[1024];
1914
        int numread = is.read(b, 0, 1024);
1915
        while(numread != -1)
1916
        {
1917
            size += numread;
1918
            numread = is.read(b, 0, 1024);
1919
        }
1920
        return size;
1921
    }
1922 5379 berkley
1923
    /**
1924
     * create system metadata with a specified id, doc and format
1925 5920 jones
     * @throws McdbDocNotFoundException
1926
     * @throws SQLException
1927
     * @throws AccessionNumberException
1928
     * @throws NumberFormatException
1929
     * @throws IOException
1930
     * @throws NoSuchAlgorithmException
1931
     * @throws PropertyNotFoundException
1932 5379 berkley
     */
1933 5920 jones
    private SystemMetadata createSystemMetadata(String localId, AuthToken token)
1934
        throws McdbDocNotFoundException, NumberFormatException, AccessionNumberException,
1935
        SQLException, NoSuchAlgorithmException, IOException, PropertyNotFoundException, BaseException {
1936
1937 5379 berkley
        IdentifierManager im = IdentifierManager.getInstance();
1938 5441 berkley
        Hashtable<String, Object> docInfo = im.getDocumentInfo(localId);
1939 5920 jones
1940 5379 berkley
        //get the document text
1941
        int rev = im.getLatestRevForLocalId(localId);
1942
        Identifier identifier = new Identifier();
1943 5920 jones
        try {
1944 5798 berkley
            identifier.setValue(im.getGUID(localId, rev));
1945 5920 jones
        } catch (McdbDocNotFoundException mcdbe) {
1946
            //we're creating a new SM doc for a doc that is not in the identifier table
1947
            //so we need to add it to
1948 5798 berkley
            System.out.println("No guid in the identifier table.  adding it for " + localId);
1949
            im.createMapping(localId, localId);
1950
            System.out.println("mapping created for " + localId);
1951
            AccessionNumber accNum = new AccessionNumber(localId, "NONE");
1952
            identifier.setValue(im.getGUID(accNum.getDocid(), rev));
1953
        }
1954 5920 jones
1955 5798 berkley
        System.out.println("creating system metadata for guid " + identifier.getValue());
1956 5379 berkley
        InputStream is = this.get(token, identifier);
1957 5920 jones
        SystemMetadata sm = new SystemMetadata();
1958 5379 berkley
1959
        //set the id
1960
        sm.setIdentifier(identifier);
1961 5920 jones
1962 5379 berkley
        //set the object format
1963 5920 jones
        String doctype = (String) docInfo.get("doctype");
1964
        ObjectFormat format = ObjectFormat.convert((String) docInfo.get("doctype"));
1965
        if (format == null) {
1966
            if (doctype.trim().equals("BIN")) {
1967 5521 berkley
                format = ObjectFormat.OCTET_STREAM;
1968 5920 jones
            } else {
1969 5379 berkley
                format = ObjectFormat.convert("text/plain");
1970
            }
1971
        }
1972
        sm.setObjectFormat(format);
1973 5920 jones
1974 5379 berkley
        //create the checksum
1975
        String checksumS = checksum(is);
1976
        ChecksumAlgorithm ca = ChecksumAlgorithm.convert("MD5");
1977
        Checksum checksum = new Checksum();
1978
        checksum.setValue(checksumS);
1979
        checksum.setAlgorithm(ca);
1980
        sm.setChecksum(checksum);
1981 5920 jones
1982 5379 berkley
        //set the size
1983
        is = this.get(token, identifier);
1984
        sm.setSize(sizeOfStream(is));
1985 5920 jones
1986 5379 berkley
        //submitter
1987
        Principal p = new Principal();
1988 5920 jones
        p.setValue((String) docInfo.get("user_owner"));
1989 5379 berkley
        sm.setSubmitter(p);
1990
        sm.setRightsHolder(p);
1991 5920 jones
        try {
1992
            Date dateCreated = parseMetacatDate((String) docInfo.get("date_created"));
1993 5379 berkley
            sm.setDateUploaded(dateCreated);
1994 5920 jones
            Date dateUpdated = parseMetacatDate((String) docInfo.get("date_updated"));
1995 5379 berkley
            sm.setDateSysMetadataModified(dateUpdated);
1996 5920 jones
        } catch (Exception e) {
1997 5428 berkley
            System.out.println("POSSIBLE ERROR: couldn't parse a date: " + e.getMessage());
1998 5379 berkley
            Date dateCreated = new Date();
1999
            sm.setDateUploaded(dateCreated);
2000
            Date dateUpdated = new Date();
2001
            sm.setDateSysMetadataModified(dateUpdated);
2002
        }
2003
        NodeReference nr = new NodeReference();
2004 5920 jones
        nr.setValue(PropertyService.getProperty("dataone.memberNodeId"));
2005 5379 berkley
        sm.setOriginMemberNode(nr);
2006
        sm.setAuthoritativeMemberNode(nr);
2007 5920 jones
2008
        // TODO: Need to set describes/describedBy
2009
2010 5379 berkley
        return sm;
2011
    }
2012 5870 berkley
2013
    /**
2014
     * create the listObjects pathQuery document
2015
     */
2016 5921 jones
//    private String createListObjectsPathQueryDocument()
2017
//        throws PropertyNotFoundException
2018
//    {
2019
//        String s = "<pathquery>";
2020
//        s += "<returndoctype>" + PropertyService.getProperty("crudService.listObjects.ReturnDoctype") + "</returndoctype>";
2021
//        s += "<returnfield>" + PropertyService.getProperty("crudService.listObjects.ReturnField.1") + "</returnfield>";
2022
//        s += "<returnfield>" + PropertyService.getProperty("crudService.listObjects.ReturnField.2") + "</returnfield>";
2023
//        s += "<returnfield>" + PropertyService.getProperty("crudService.listObjects.ReturnField.3") + "</returnfield>";
2024
//        s += "<returnfield>" + PropertyService.getProperty("crudService.listObjects.ReturnField.4") + "</returnfield>";
2025
//        s += "<returnfield>" + PropertyService.getProperty("crudService.listObjects.ReturnField.5") + "</returnfield>";
2026
//        s += "<returnfield>" + PropertyService.getProperty("crudService.listObjects.ReturnField.6") + "</returnfield>";
2027
//        s += "<returnfield>" + PropertyService.getProperty("crudService.listObjects.ReturnField.7") + "</returnfield>";
2028
//        s += "<querygroup operator=\"UNION\"><queryterm casesensitive=\"false\" searchmode=\"contains\">";
2029
//        s += "<value>%</value>";
2030
//        s += "<pathexpr>" + PropertyService.getProperty("crudService.listObjects.ReturnField.3") + "</pathexpr>";
2031
//        s += "</queryterm></querygroup></pathquery>";
2032
//
2033
//        return s;
2034
//    }
2035 5298 jones
}