Project

General

Profile

1 8810 leinfelder
/**
2
 *  '$RCSfile$'
3
 *  Copyright: 2011 Regents of the University of California and the
4
 *              National Center for Ecological Analysis and Synthesis
5
 *
6
 *   '$Author$'
7
 *     '$Date$'
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.restservice.v1;
24
25
import java.io.File;
26
import java.io.FileInputStream;
27
import java.io.IOException;
28
import java.io.InputStream;
29
import java.io.OutputStream;
30
import java.util.Date;
31
import java.util.Enumeration;
32
import java.util.Map;
33
34
import javax.servlet.ServletContext;
35
import javax.servlet.http.HttpServletRequest;
36
import javax.servlet.http.HttpServletResponse;
37
import javax.xml.parsers.ParserConfigurationException;
38
39
import org.apache.commons.fileupload.FileUploadException;
40
import org.apache.commons.io.IOUtils;
41
import org.apache.log4j.Logger;
42
import org.dataone.client.v2.formats.ObjectFormatInfo;
43 9833 tao
import org.dataone.exceptions.MarshallingException;
44 8810 leinfelder
import org.dataone.service.exceptions.BaseException;
45
import org.dataone.service.exceptions.IdentifierNotUnique;
46
import org.dataone.service.exceptions.InsufficientResources;
47
import org.dataone.service.exceptions.InvalidRequest;
48
import org.dataone.service.exceptions.InvalidSystemMetadata;
49
import org.dataone.service.exceptions.InvalidToken;
50
import org.dataone.service.exceptions.NotAuthorized;
51
import org.dataone.service.exceptions.NotFound;
52
import org.dataone.service.exceptions.NotImplemented;
53
import org.dataone.service.exceptions.ServiceFailure;
54
import org.dataone.service.exceptions.UnsupportedType;
55
import org.dataone.service.exceptions.VersionMismatch;
56
import org.dataone.service.types.v1.AccessPolicy;
57
import org.dataone.service.types.v1.Checksum;
58
import org.dataone.service.types.v1.ChecksumAlgorithmList;
59
import org.dataone.service.types.v1.DescribeResponse;
60
import org.dataone.service.types.v1.Event;
61
import org.dataone.service.types.v1.Identifier;
62
import org.dataone.service.types.v1.Log;
63
import org.dataone.service.types.v1.NodeReference;
64
import org.dataone.service.types.v1.ObjectFormat;
65
import org.dataone.service.types.v1.ObjectFormatIdentifier;
66
import org.dataone.service.types.v1.ObjectFormatList;
67
import org.dataone.service.types.v1.ObjectList;
68
import org.dataone.service.types.v1.ObjectLocationList;
69
import org.dataone.service.types.v1.Permission;
70
import org.dataone.service.types.v1.Replica;
71
import org.dataone.service.types.v1.ReplicationPolicy;
72
import org.dataone.service.types.v1.ReplicationStatus;
73
import org.dataone.service.types.v1.Subject;
74
import org.dataone.service.types.v1.SystemMetadata;
75
import org.dataone.service.util.Constants;
76
import org.dataone.service.util.DateTimeMarshaller;
77
import org.dataone.service.util.EncodingUtilities;
78
import org.dataone.service.util.ExceptionHandler;
79
import org.dataone.service.util.TypeMarshaller;
80
import org.xml.sax.SAXException;
81
82
import edu.ucsb.nceas.metacat.dataone.v1.CNodeService;
83
import edu.ucsb.nceas.metacat.properties.PropertyService;
84 9297 tao
import edu.ucsb.nceas.metacat.restservice.D1HttpRequest;
85 8810 leinfelder
import edu.ucsb.nceas.metacat.restservice.D1ResourceHandler;
86
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
87
88
/**
89
 * CN REST service implementation handler
90
 *
91
 * ****************** CNCore -- DONE create() - POST /d1/cn/object/PID
92
 * listFormats() - GET /d1/cn/formats getFormat() - GET /d1/cn/formats/FMTID
93
 * getLogRecords - GET /d1/cn/log reserveIdentifier() - POST /d1/cn/reserve
94
 * listNodes() - Not implemented registerSystemMetadata() - POST /d1/meta/PID
95
 *
96
 * CNRead -- DONE get() - GET /d1/cn/object/PID getSystemMetadata() - GET
97
 * /d1/cn/meta/PID resolve() - GET /d1/cn/resolve/PID assertRelation() - GET
98
 * /d1/cn/assertRelation/PID getChecksum() - GET /d1/cn/checksum search() - Not
99
 * implemented in Metacat
100
 *
101
 * CNAuthorization setOwner() - PUT /d1/cn/owner/PID isAuthorized() - GET
102
 * /d1/cn/isAuthorized/PID setAccessPolicy() - POST /d1/cn/accessRules
103
 *
104
 * CNIdentity - not implemented at all on Metacat
105
 *
106
 * CNReplication setReplicationStatus() - PUT /replicaNotifications/PID
107
 * updateReplicationMetadata() - PUT /replicaMetadata/PID setReplicationPolicy()
108
 * - PUT /replicaPolicies/PID isNodeAuthorized() - GET
109
 * /replicaAuthorizations/PID
110
 *
111
 * CNRegister -- not implemented at all in Metacat ******************
112
 *
113
 * @author leinfelder
114
 *
115
 */
116
public class CNResourceHandler extends D1ResourceHandler {
117
118
    /** CN-specific operations **/
119
    protected static final String RESOURCE_RESERVE = "reserve";
120
    protected static final String RESOURCE_FORMATS = "formats";
121
    protected static final String RESOURCE_RESOLVE = "resolve";
122
    protected static final String RESOURCE_OWNER = "owner";
123
    protected static final String RESOURCE_REPLICATION_POLICY = "replicaPolicies";
124
    protected static final String RESOURCE_REPLICATION_META = "replicaMetadata";
125
    protected static final String RESOURCE_REPLICATION_AUTHORIZED = "replicaAuthorizations";
126
    protected static final String RESOURCE_REPLICATION_NOTIFY = "replicaNotifications";
127
128
    public CNResourceHandler(ServletContext servletContext,
129
            HttpServletRequest request, HttpServletResponse response) {
130
        super(servletContext, request, response);
131
        logMetacat = Logger.getLogger(CNResourceHandler.class);
132
    }
133
134
    /**
135
     * This function is called from REST API servlet and handles each request to
136
     * the servlet
137
     *
138
     * @param httpVerb
139
     *            (GET, POST, PUT or DELETE)
140
     */
141
    @Override
142
    public void handle(byte httpVerb) {
143
        // prepare the handler
144
        super.handle(httpVerb);
145
146
        try {
147
148
        	// only service requests if we have D1 configured
149
        	if (!isD1Enabled()) {
150
        		ServiceFailure se = new ServiceFailure("0000", "DataONE services are not enabled on this node");
151
                serializeException(se, response.getOutputStream());
152
                return;
153
        	}
154
155
            // get the resource
156
            String resource = request.getPathInfo();
157
            resource = resource.substring(resource.indexOf("/") + 1);
158
159
            // for the rest of the resouce
160
            String extra = null;
161
162
            logMetacat.debug("handling verb " + httpVerb
163
                    + " request with resource '" + resource + "'");
164
            boolean status = false;
165
166
            if (resource != null) {
167
168
                if (resource.startsWith(RESOURCE_ACCESS_RULES)
169
                        && httpVerb == PUT) {
170
                    logMetacat.debug("Setting access policy");
171
                    // after the command
172
                    extra = parseTrailing(resource, RESOURCE_ACCESS_RULES);
173 9297 tao
                    extra = decode(extra);
174 8810 leinfelder
                    setAccess(extra);
175
                    status = true;
176
                    logMetacat.debug("done setting access");
177
178
                } else if (resource.startsWith(RESOURCE_META)) {
179
                    logMetacat.debug("Using resource: " + RESOURCE_META);
180
181
                    // after the command
182
                    extra = parseTrailing(resource, RESOURCE_META);
183 9297 tao
                    extra = decode(extra);
184 8810 leinfelder
                    // get
185
                    if (httpVerb == GET) {
186
                        getSystemMetadataObject(extra);
187
                        status = true;
188
                    }
189
                    // post to register system metadata
190
                    if (httpVerb == POST) {
191
                        registerSystemMetadata();
192
                        status = true;
193
                    }
194
195
                } else if (resource.startsWith(RESOURCE_RESERVE)) {
196
                    // reserve the ID (in params)
197
                    if (httpVerb == POST) {
198
                        reserve();
199
                        status = true;
200
                    }
201
                } else if (resource.startsWith(RESOURCE_RESOLVE)) {
202
203
                    // after the command
204
                    extra = parseTrailing(resource, RESOURCE_RESOLVE);
205 9297 tao
                    extra = decode(extra);
206 8810 leinfelder
                    // resolve the object location
207
                    if (httpVerb == GET) {
208
                        resolve(extra);
209
                        status = true;
210
                    }
211
                } else if (resource.startsWith(RESOURCE_OWNER)) {
212
213
                    // after the command
214
                    extra = parseTrailing(resource, RESOURCE_OWNER);
215 9297 tao
                    extra = decode(extra);
216 8810 leinfelder
                    // set the owner
217
                    if (httpVerb == PUT) {
218
                        owner(extra);
219
                        status = true;
220
                    }
221
                } else if (resource.startsWith(RESOURCE_IS_AUTHORIZED)) {
222
223
                    // after the command
224
                    extra = parseTrailing(resource, RESOURCE_IS_AUTHORIZED);
225 9297 tao
                    extra = decode(extra);
226 8810 leinfelder
                    // authorized?
227
                    if (httpVerb == GET) {
228
                        isAuthorized(extra);
229
                        status = true;
230
                    }
231
                } else if (resource.startsWith(RESOURCE_OBJECTS)) {
232
                    logMetacat.debug("Using resource 'object'");
233
                    logMetacat
234
                            .debug("D1 Rest: Starting resource processing...");
235
236
                    // after the command
237
                    extra = parseTrailing(resource, RESOURCE_OBJECTS);
238 9297 tao
                    extra = decode(extra);
239 8810 leinfelder
                    logMetacat.debug("objectId: " + extra);
240
                    logMetacat.debug("verb:" + httpVerb);
241
242
                    if (httpVerb == GET) {
243
                        if (extra != null) {
244
                            getObject(extra);
245
                        } else {
246
                            listObjects();
247
                        }
248
                        status = true;
249
                    } else if (httpVerb == POST) {
250
                        putObject(FUNCTION_NAME_INSERT);
251
                        status = true;
252
                    } else if (httpVerb == HEAD) {
253
                        describeObject(extra);
254
                        status = true;
255
                    } else if (httpVerb == DELETE) {
256
                        deleteObject(extra);
257
                        status = true;
258
                    }
259
260
                } else if (resource.startsWith(RESOURCE_FORMATS)) {
261
                    logMetacat.debug("Using resource: " + RESOURCE_FORMATS);
262
263
                    // after the command
264
                    extra = parseTrailing(resource, RESOURCE_FORMATS);
265 9297 tao
                    extra = decode(extra);
266 8810 leinfelder
                    // handle each verb
267
                    if (httpVerb == GET) {
268
                        if (extra == null) {
269
                            // list the formats collection
270
                            listFormats();
271
                        } else {
272
                            // get the specified format
273
                            getFormat(extra);
274
                        }
275
                        status = true;
276
                    }
277
278
                } else if (resource.startsWith(RESOURCE_LOG)) {
279
                    logMetacat.debug("Using resource: " + RESOURCE_LOG);
280
                    // handle log events
281
                    if (httpVerb == GET) {
282
                        getLog();
283
                        status = true;
284
                    }
285
286
                } else if (resource.startsWith(Constants.RESOURCE_ARCHIVE)) {
287
                    logMetacat.debug("Using resource " + Constants.RESOURCE_ARCHIVE);
288
                    // handle archive events
289
                    if (httpVerb == PUT) {
290
                        extra = parseTrailing(resource, Constants.RESOURCE_ARCHIVE);
291 9297 tao
                        extra = decode(extra);
292 8810 leinfelder
                        archive(extra);
293
                        status = true;
294
                    }
295
                } else if (resource.startsWith(Constants.RESOURCE_CHECKSUM)) {
296
                    logMetacat.debug("Using resource: " + Constants.RESOURCE_CHECKSUM);
297
298
                    // after the command
299
                    extra = parseTrailing(resource, Constants.RESOURCE_CHECKSUM);
300 9297 tao
                    extra = decode(extra);
301 8810 leinfelder
                    // handle checksum requests
302
                    if (httpVerb == GET) {
303
304
                    	if (extra != null && extra.length() > 0) {
305
	                        checksum(extra);
306
	                        status = true;
307
                    	} else {
308
                    		listChecksumAlgorithms();
309
                    		status = true;
310
                    	}
311
312
                    }
313
314
                } else if (resource.startsWith(RESOURCE_REPLICATION_POLICY)
315
                        && httpVerb == PUT) {
316
317
                    logMetacat.debug("Using resource: "
318
                            + RESOURCE_REPLICATION_POLICY);
319
                    // get the trailing pid
320
                    extra = parseTrailing(resource, RESOURCE_REPLICATION_POLICY);
321 9297 tao
                    extra = decode(extra);
322 8810 leinfelder
                    setReplicationPolicy(extra);
323
                    status = true;
324
325
                } else if (resource.startsWith(RESOURCE_REPLICATION_META)
326
                        && httpVerb == PUT) {
327
328
                    logMetacat.debug("Using resource: "
329
                            + RESOURCE_REPLICATION_META);
330
                    // get the trailing pid
331
                    extra = parseTrailing(resource, RESOURCE_REPLICATION_META);
332 9297 tao
                    extra = decode(extra);
333 8810 leinfelder
                    updateReplicationMetadata(extra);
334
                    status = true;
335
336
                } else if (resource.startsWith(RESOURCE_REPLICATION_NOTIFY)
337
                        && httpVerb == PUT) {
338
339
                    logMetacat.debug("Using resource: "
340
                            + RESOURCE_REPLICATION_NOTIFY);
341
                    // get the trailing pid
342
                    extra = parseTrailing(resource, RESOURCE_REPLICATION_NOTIFY);
343 9297 tao
                    extra = decode(extra);
344 8810 leinfelder
                    setReplicationStatus(extra);
345
                    status = true;
346
347
                } else if (resource.startsWith(RESOURCE_REPLICATION_AUTHORIZED)
348
                        && httpVerb == GET) {
349
350
                    logMetacat.debug("Using resource: "
351
                            + RESOURCE_REPLICATION_AUTHORIZED);
352
                    // get the trailing pid
353
                    extra = parseTrailing(resource,
354
                            RESOURCE_REPLICATION_AUTHORIZED);
355 9297 tao
                    extra = decode(extra);
356 8810 leinfelder
                    isNodeAuthorized(extra);
357
                    status = true;
358
359
                } else if (resource.startsWith(Constants.RESOURCE_MONITOR_PING)) {
360
                    if (httpVerb == GET) {
361
                    	// after the command
362
                        extra = parseTrailing(resource, Constants.RESOURCE_MONITOR_PING);
363 9297 tao
                        extra = decode(extra);
364 8810 leinfelder
                        logMetacat.debug("processing ping request");
365
                        Date result = CNodeService.getInstance(request).ping();
366
                        // TODO: send to output
367
                        status = true;
368
                    }
369
                } else if (resource.startsWith(Constants.RESOURCE_META_OBSOLETEDBY)
370
                        && httpVerb == PUT) {
371
372
                    logMetacat.debug("Using resource: "
373
                            + Constants.RESOURCE_META_OBSOLETEDBY);
374
                    // get the trailing pid
375
                    extra = parseTrailing(resource, Constants.RESOURCE_META_OBSOLETEDBY);
376 9297 tao
                    extra = decode(extra);
377 8810 leinfelder
                    setObsoletedBy(extra);
378
                    status = true;
379
                } else if (resource.startsWith(Constants.RESOURCE_REPLICATION_DELETE_REPLICA)
380
                        && httpVerb == PUT) {
381
382
                    logMetacat.debug("Using resource: "
383
                            + Constants.RESOURCE_REPLICATION_DELETE_REPLICA);
384
                    // get the trailing pid
385
                    extra = parseTrailing(resource, Constants.RESOURCE_REPLICATION_DELETE_REPLICA);
386 9297 tao
                    extra = decode(extra);
387 8810 leinfelder
                    deleteReplica(extra);
388
                    status = true;
389
                }
390
391
                if (!status) {
392
                    throw new ServiceFailure("0000", "Unknown error, status = "
393
                            + status);
394
                }
395
            } else {
396
                throw new InvalidRequest("0000", "No resource matched for "
397
                        + resource);
398
            }
399
        } catch (BaseException be) {
400
            // report Exceptions as clearly and generically as possible
401
            OutputStream out = null;
402
            try {
403
                out = response.getOutputStream();
404
            } catch (IOException ioe) {
405
                logMetacat.error("Could not get output stream from response",
406
                        ioe);
407
            }
408
            serializeException(be, out);
409
        } catch (Exception e) {
410
            // report Exceptions as clearly and generically as possible
411
            logMetacat.error(e.getClass() + ": " + e.getMessage(), e);
412
            OutputStream out = null;
413
            try {
414
                out = response.getOutputStream();
415
            } catch (IOException ioe) {
416
                logMetacat.error("Could not get output stream from response",
417
                        ioe);
418
            }
419
            ServiceFailure se = new ServiceFailure("0000", e.getMessage());
420
            serializeException(se, out);
421
        }
422
    }
423
424
    /**
425
     * Get the checksum for the given guid
426
     *
427
     * @param guid
428
     * @throws NotImplemented
429
     * @throws InvalidRequest
430
     * @throws NotFound
431
     * @throws NotAuthorized
432
     * @throws ServiceFailure
433
     * @throws InvalidToken
434
     * @throws IOException
435 9833 tao
     * @throws MarshallingException
436 8810 leinfelder
     */
437
    private void checksum(String guid) throws InvalidToken, ServiceFailure,
438
            NotAuthorized, NotFound, InvalidRequest, NotImplemented,
439 9833 tao
            MarshallingException, IOException {
440 8810 leinfelder
        Identifier guidid = new Identifier();
441
        guidid.setValue(guid);
442
        logMetacat.debug("getting checksum for object " + guid);
443
        Checksum c = CNodeService.getInstance(request).getChecksum(session,
444
                guidid);
445
        logMetacat.debug("got checksum " + c.getValue());
446
        response.setStatus(200);
447
        logMetacat.debug("serializing response");
448
        TypeMarshaller.marshalTypeToOutputStream(c, response.getOutputStream());
449
        logMetacat.debug("done serializing response.");
450
451
    }
452
453
    /**
454
     * get the logs based on passed params. Available params are token,
455
     * fromDate, toDate, event. See
456
     * http://mule1.dataone.org/ArchitectureDocs/mn_api_crud
457
     * .html#MN_crud.getLogRecords for more info
458
     *
459
     * @throws NotImplemented
460
     * @throws InvalidRequest
461
     * @throws NotAuthorized
462
     * @throws ServiceFailure
463
     * @throws InvalidToken
464
     * @throws IOException
465 9833 tao
     * @throws MarshallingException
466 8810 leinfelder
     * @throws InsufficientResources
467
     */
468
    private void getLog() throws InvalidToken, ServiceFailure, NotAuthorized,
469 9833 tao
            InvalidRequest, NotImplemented, IOException, MarshallingException, InsufficientResources {
470 8810 leinfelder
471
        Date fromDate = null;
472
        Date toDate = null;
473
        Event event = null;
474
        Integer start = null;
475
        Integer count = null;
476
        String pidFilter = null;
477
478
        try {
479
            String fromDateS = params.get("fromDate")[0];
480
            logMetacat.debug("param fromDateS: " + fromDateS);
481
            fromDate = DateTimeMarshaller.deserializeDateToUTC(fromDateS);
482
        } catch (Exception e) {
483
            logMetacat.warn("Could not parse fromDate: " + e.getMessage());
484
        }
485
        try {
486
            String toDateS = params.get("toDate")[0];
487
            logMetacat.debug("param toDateS: " + toDateS);
488
            toDate = DateTimeMarshaller.deserializeDateToUTC(toDateS);
489
        } catch (Exception e) {
490
            logMetacat.warn("Could not parse toDate: " + e.getMessage());
491
        }
492
        try {
493
            String eventS = params.get("event")[0];
494
            event = Event.convert(eventS);
495
        } catch (Exception e) {
496
            logMetacat.warn("Could not parse event: " + e.getMessage());
497
        }
498
        logMetacat.debug("fromDate: " + fromDate + " toDate: " + toDate);
499
500
        try {
501
            start = Integer.parseInt(params.get("start")[0]);
502
        } catch (Exception e) {
503
            logMetacat.warn("Could not parse start: " + e.getMessage());
504
        }
505
        try {
506
            count = Integer.parseInt(params.get("count")[0]);
507
        } catch (Exception e) {
508
            logMetacat.warn("Could not parse count: " + e.getMessage());
509
        }
510
511
        try {
512
            pidFilter = params.get("pidFilter")[0];
513
        } catch (Exception e) {
514
            logMetacat.warn("Could not parse pidFilter: " + e.getMessage());
515
        }
516
517
        logMetacat.debug("calling getLogRecords");
518
        Log log = CNodeService.getInstance(request).getLogRecords(session,
519
                fromDate, toDate, event, pidFilter, start, count);
520
521
        OutputStream out = response.getOutputStream();
522
        response.setStatus(200);
523
        response.setContentType("text/xml");
524
525
        TypeMarshaller.marshalTypeToOutputStream(log, out);
526
527
    }
528
529
    /**
530
     * Implements REST version of DataONE CRUD API --> get
531
     *
532
     * @param guid
533
     *            ID of data object to be read
534
     * @throws NotImplemented
535
     * @throws InvalidRequest
536
     * @throws NotFound
537
     * @throws NotAuthorized
538
     * @throws ServiceFailure
539
     * @throws InvalidToken
540
     * @throws IOException
541
     */
542
    protected void getObject(String guid) throws InvalidToken, ServiceFailure,
543
            NotAuthorized, NotFound, InvalidRequest, NotImplemented,
544
            IOException {
545
546
        Identifier id = new Identifier();
547
        id.setValue(guid);
548
549
        SystemMetadata sm = CNodeService.getInstance(request)
550
                .getSystemMetadata(session, id);
551
552
        // set the headers for the content
553
        String mimeType = ObjectFormatInfo.instance().getMimeType(sm.getFormatId().getValue());
554
        if (mimeType == null) {
555
        	mimeType = "application/octet-stream";
556
        }
557
        String extension = ObjectFormatInfo.instance().getExtension(sm.getFormatId().getValue());
558
        String filename = id.getValue();
559 10054 tao
        if (extension != null && filename != null && !filename.endsWith(extension)) {
560 8810 leinfelder
        	filename = id.getValue() + extension;
561
        }
562
        response.setContentType(mimeType);
563
        response.setHeader("Content-Disposition", "inline; filename=" + filename);
564
565
        InputStream data = CNodeService.getInstance(request).get(session, id);
566
567
        OutputStream out = response.getOutputStream();
568
        response.setStatus(200);
569
        IOUtils.copyLarge(data, out);
570
571
    }
572
573
    /**
574
     * Implements REST version of DataONE CRUD API --> getSystemMetadata
575
     *
576
     * @param guid
577
     *            ID of data object to be read
578
     * @throws NotImplemented
579
     * @throws InvalidRequest
580
     * @throws NotFound
581
     * @throws NotAuthorized
582
     * @throws ServiceFailure
583
     * @throws InvalidToken
584
     * @throws IOException
585 9833 tao
     * @throws MarshallingException
586 8810 leinfelder
     */
587
    protected void getSystemMetadataObject(String guid) throws InvalidToken,
588
            ServiceFailure, NotAuthorized, NotFound, InvalidRequest,
589 9833 tao
            NotImplemented, IOException, MarshallingException {
590 8810 leinfelder
591
        Identifier id = new Identifier();
592
        id.setValue(guid);
593
        SystemMetadata sysmeta = CNodeService.getInstance(request)
594
                .getSystemMetadata(session, id);
595
596
        response.setContentType("text/xml");
597
        response.setStatus(200);
598
        OutputStream out = response.getOutputStream();
599
600
        // Serialize and write it to the output stream
601
        TypeMarshaller.marshalTypeToOutputStream(sysmeta, out);
602
    }
603
604
    /**
605
     * Earthgrid API > Put Service >Put Function : calls MetacatHandler >
606
     * handleInsertOrUpdateAction
607
     *
608
     * @param guid
609
     *            - ID of data object to be inserted or updated. If action is
610
     *            update, the pid is the existing pid. If insert, the pid is the
611
     *            new one
612
     * @throws InvalidRequest
613
     * @throws ServiceFailure
614
     * @throws IdentifierNotUnique
615 9833 tao
     * @throws MarshallingException
616 8810 leinfelder
     * @throws NotImplemented
617
     * @throws InvalidSystemMetadata
618
     * @throws InsufficientResources
619
     * @throws UnsupportedType
620
     * @throws NotAuthorized
621
     * @throws InvalidToken
622
     * @throws IOException
623
     * @throws IllegalAccessException
624
     * @throws InstantiationException
625
     */
626
    protected void putObject(String action) throws ServiceFailure,
627 9833 tao
            InvalidRequest, IdentifierNotUnique, MarshallingException, InvalidToken,
628 8810 leinfelder
            NotAuthorized, UnsupportedType, InsufficientResources,
629
            InvalidSystemMetadata, NotImplemented, IOException,
630
            InstantiationException, IllegalAccessException {
631
632
        // Read the incoming data from its Mime Multipart encoding
633
        Map<String, File> files = collectMultipartFiles();
634
635
	    // get the encoded pid string from the body and make the object
636
        String pidString = multipartparams.get("pid").get(0);
637
        Identifier pid = new Identifier();
638
        pid.setValue(pidString);
639
640
        logMetacat.debug("putObject: " + pid.getValue() + "/" + action);
641
642
        InputStream object = null;
643
        InputStream sysmeta = null;
644
645
        File smFile = files.get("sysmeta");
646
        sysmeta = new FileInputStream(smFile);
647
        File objFile = files.get("object");
648
        object = new FileInputStream(objFile);
649
650
        if (action.equals(FUNCTION_NAME_INSERT)) { // handle inserts
651
652
            logMetacat.debug("Commence creation...");
653
            SystemMetadata smd = TypeMarshaller.unmarshalTypeFromStream(
654
                    SystemMetadata.class, sysmeta);
655
656
657
            logMetacat.debug("creating object with pid " + pid.getValue());
658
            Identifier rId = CNodeService.getInstance(request).create(session, pid, object, smd);
659
660
            OutputStream out = response.getOutputStream();
661
            response.setStatus(200);
662
            response.setContentType("text/xml");
663
664
            TypeMarshaller.marshalTypeToOutputStream(rId, out);
665
666
        } else {
667
            throw new InvalidRequest("1000", "Operation must be create.");
668
        }
669
    }
670
671
    /**
672
     * List the object formats registered with the system
673
     *
674
     * @throws NotImplemented
675
     * @throws InsufficientResources
676
     * @throws NotFound
677
     * @throws ServiceFailure
678
     * @throws InvalidRequest
679
     * @throws IOException
680 9833 tao
     * @throws MarshallingException
681 8810 leinfelder
     */
682
    private void listFormats() throws InvalidRequest, ServiceFailure, NotFound,
683 9833 tao
            InsufficientResources, NotImplemented, IOException, MarshallingException {
684 8810 leinfelder
        logMetacat.debug("Entering listFormats()");
685
686
        ObjectFormatList objectFormatList = CNodeService.getInstance(request)
687
                .listFormats();
688
        // get the response output stream
689
        OutputStream out = response.getOutputStream();
690
        response.setStatus(200);
691
        response.setContentType("text/xml");
692
693
        // style the object with a processing directive
694
        String stylesheet = null;
695
        try {
696 9237 leinfelder
            stylesheet = PropertyService.getProperty("dataone.types.xsl.v1");
697 8810 leinfelder
        } catch (PropertyNotFoundException e) {
698
            logMetacat.warn("Could not locate DataONE types XSLT: "
699
                    + e.getMessage());
700
        }
701
702
        TypeMarshaller.marshalTypeToOutputStream(objectFormatList, out,
703
                stylesheet);
704
705
    }
706
707
    private void listChecksumAlgorithms() throws IOException, ServiceFailure,
708 9833 tao
			NotImplemented, MarshallingException {
709 8810 leinfelder
		logMetacat.debug("Entering listFormats()");
710
711
		ChecksumAlgorithmList result = CNodeService.getInstance(request).listChecksumAlgorithms();
712
713
		// get the response output stream
714
		OutputStream out = response.getOutputStream();
715
		response.setStatus(200);
716
		response.setContentType("text/xml");
717
718
		TypeMarshaller.marshalTypeToOutputStream(result, out);
719
720
	}
721
722
    /**
723
     * http://mule1.dataone.org/ArchitectureDocs-current/apis/CN_APIs.html#CNRead.describe
724
     * @param pid
725
     * @throws InvalidToken
726
     * @throws ServiceFailure
727
     * @throws NotAuthorized
728
     * @throws NotFound
729
     * @throws NotImplemented
730
     * @throws InvalidRequest
731
     */
732
    private void describeObject(String pid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, InvalidRequest
733
    {
734
        response.setContentType("text/xml");
735
736
        Identifier id = new Identifier();
737
        id.setValue(pid);
738
739
        DescribeResponse dr = null;
740
        try {
741
            dr = CNodeService.getInstance(request).describe(session, id);
742
        } catch (BaseException e) {
743
        	response.setStatus(e.getCode());
744
        	response.addHeader("DataONE-Exception-Name", e.getClass().getName());
745
            response.addHeader("DataONE-Exception-DetailCode", e.getDetail_code());
746
            response.addHeader("DataONE-Exception-Description", e.getDescription());
747
            response.addHeader("DataONE-Exception-PID", id.getValue());
748
            return;
749
		}
750
751
        response.setStatus(200);
752
        //response.addHeader("pid", pid);
753
        response.addHeader("DataONE-Checksum", dr.getDataONE_Checksum().getAlgorithm() + "," + dr.getDataONE_Checksum().getValue());
754
        response.addHeader("Content-Length", dr.getContent_Length() + "");
755
        response.addHeader("Last-Modified", DateTimeMarshaller.serializeDateToUTC(dr.getLast_Modified()));
756
        response.addHeader("DataONE-ObjectFormat", dr.getDataONE_ObjectFormatIdentifier().getValue());
757
        response.addHeader("DataONE-SerialVersion", dr.getSerialVersion().toString());
758
759
    }
760
761
    /**
762
     * Handle delete
763
     * @param pid ID of data object to be deleted
764
     * @throws IOException
765
     * @throws InvalidRequest
766
     * @throws NotImplemented
767
     * @throws NotFound
768
     * @throws NotAuthorized
769
     * @throws ServiceFailure
770
     * @throws InvalidToken
771 9833 tao
     * @throws MarshallingException
772 8810 leinfelder
     */
773 9833 tao
    private void deleteObject(String pid) throws IOException, InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, InvalidRequest, MarshallingException
774 8810 leinfelder
    {
775
776
        OutputStream out = response.getOutputStream();
777
        response.setStatus(200);
778
        response.setContentType("text/xml");
779
780
        Identifier id = new Identifier();
781
        id.setValue(pid);
782
783
        logMetacat.debug("Calling delete for identifier " + pid);
784
        CNodeService.getInstance(request).delete(session, id);
785
        TypeMarshaller.marshalTypeToOutputStream(id, out);
786
787
    }
788
789
    /**
790
     * Archives the given pid
791
     * @param pid
792
     * @throws InvalidToken
793
     * @throws ServiceFailure
794
     * @throws NotAuthorized
795
     * @throws NotFound
796
     * @throws NotImplemented
797
     * @throws IOException
798 9833 tao
     * @throws MarshallingException
799 8810 leinfelder
     * @throws InvalidRequest
800
     */
801 9833 tao
    private void archive(String pid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, IOException, MarshallingException, InvalidRequest {
802 8810 leinfelder
803
        OutputStream out = response.getOutputStream();
804
        response.setStatus(200);
805
        response.setContentType("text/xml");
806
807
        Identifier id = new Identifier();
808
        id.setValue(pid);
809
810
        logMetacat.debug("Calling archive");
811
        CNodeService.getInstance(request).archive(session, id);
812
813
        TypeMarshaller.marshalTypeToOutputStream(id, out);
814
815
    }
816
817
    /**
818
     * Return the requested object format
819
     *
820
     * @param fmtidStr
821
     *            the requested format identifier as a string
822
     * @throws NotImplemented
823
     * @throws InsufficientResources
824
     * @throws NotFound
825
     * @throws ServiceFailure
826
     * @throws InvalidRequest
827
     * @throws IOException
828 9833 tao
     * @throws MarshallingException
829 8810 leinfelder
     */
830
    private void getFormat(String fmtidStr) throws InvalidRequest,
831
            ServiceFailure, NotFound, InsufficientResources, NotImplemented,
832 9833 tao
            IOException, MarshallingException {
833 8810 leinfelder
        logMetacat.debug("Entering listFormats()");
834
835
        ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
836
        fmtid.setValue(fmtidStr);
837
838
        // get the specified object format
839
        ObjectFormat objectFormat = CNodeService.getInstance(request)
840
                .getFormat(fmtid);
841
842
        OutputStream out = response.getOutputStream();
843
        response.setStatus(200);
844
        response.setContentType("text/xml");
845
846
        TypeMarshaller.marshalTypeToOutputStream(objectFormat, out);
847
848
    }
849
850
    /**
851
     * Reserve the given Identifier
852
     *
853
     * @throws InvalidToken
854
     * @throws ServiceFailure
855
     * @throws NotAuthorized
856
     * @throws IdentifierNotUnique
857
     * @throws NotImplemented
858
     * @throws InvalidRequest
859
     */
860
    private void reserve()
861
        throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique,
862
        NotImplemented, InvalidRequest {
863
        Identifier pid = null;
864
        String scope = null;
865
        String format = null;
866
867
        // Parse the params out of the multipart form data
868
        logMetacat.debug("Parsing reserve parameters from the mime multipart entity");
869
        try {
870
            collectMultipartParams();
871
872
        } catch (FileUploadException e1) {
873
            String msg = "FileUploadException: Couldn't parse the mime multipart information: " +
874
            e1.getMessage();
875
            logMetacat.debug(msg);
876
            throw new ServiceFailure("4210", msg);
877
878
        } catch (IOException e1) {
879
            String msg = "IOException: Couldn't parse the mime multipart information: " +
880
            e1.getMessage();
881
            logMetacat.debug(msg);
882
            throw new ServiceFailure("4210", msg);
883
884
        } catch (Exception e1) {
885
            String msg = "Exception: Couldn't parse the mime multipart information: " +
886
            e1.getMessage();
887
            logMetacat.debug(msg);
888
            throw new ServiceFailure("4210", msg);
889
890
        }
891
892
        // gather the params
893
        try {
894
            String id = multipartparams.get("pid").get(0);
895
            pid = new Identifier();
896
            pid.setValue(id);
897
898
        } catch (NullPointerException e) {
899
            String msg = "The 'pid' must be provided as a parameter and was not.";
900
            logMetacat.error(msg);
901
            throw new InvalidRequest("4200", msg);
902
903
        }
904
905
        // call the implementation
906
        try {
907
            Identifier resultPid = CNodeService.getInstance(request).reserveIdentifier(session, pid);
908
            OutputStream out = response.getOutputStream();
909
            response.setStatus(200);
910
            response.setContentType("text/xml");
911
            // send back the reserved pid
912
            TypeMarshaller.marshalTypeToOutputStream(resultPid, out);
913
914
        } catch (IOException e) {
915
            String msg = "Couldn't write the identifier to the response output stream: " +
916
                e.getMessage();
917
            logMetacat.debug(msg);
918
            throw new ServiceFailure("4210", msg);
919
920 9833 tao
        } catch (MarshallingException e) {
921 8810 leinfelder
            String msg = "Couldn't marshall the identifier to the response output stream: " +
922
            e.getMessage();
923
            logMetacat.debug(msg);
924
            throw new ServiceFailure("4210", msg);
925
926
        }
927
    }
928
929
    /**
930
     *
931
     * @param id
932
     * @throws InvalidRequest
933
     * @throws InvalidToken
934
     * @throws ServiceFailure
935
     * @throws NotAuthorized
936
     * @throws NotFound
937
     * @throws NotImplemented
938
     * @throws IOException
939 9833 tao
     * @throws MarshallingException
940 8810 leinfelder
     */
941
    private void resolve(String id) throws InvalidRequest, InvalidToken,
942
            ServiceFailure, NotAuthorized, NotFound, NotImplemented,
943 9833 tao
            IOException, MarshallingException {
944 8810 leinfelder
        Identifier pid = new Identifier();
945
        pid.setValue(id);
946
        ObjectLocationList locationList = CNodeService.getInstance(request)
947
                .resolve(session, pid);
948
        OutputStream out = response.getOutputStream();
949
        response.setStatus(200);
950
        response.setContentType("text/xml");
951
        TypeMarshaller.marshalTypeToOutputStream(locationList, out);
952
953
    }
954
955
    /**
956
     * Set the owner of a resource
957
     *
958
     * @param id
959
     * @throws InvalidToken
960
     * @throws ServiceFailure
961
     * @throws NotFound
962
     * @throws NotAuthorized
963
     * @throws NotImplemented
964
     * @throws InvalidRequest
965
     * @throws IllegalAccessException
966
     * @throws InstantiationException
967
     * @throws VersionMismatch
968
     */
969
    private void owner(String id)
970
        throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
971
        NotImplemented, InvalidRequest, InstantiationException,
972
        IllegalAccessException, VersionMismatch {
973
974
        Identifier pid = new Identifier();
975
        pid.setValue(id);
976
977
        long serialVersion = 0L;
978
        String serialVersionStr = null;
979
        String userIdStr = null;
980
        Subject userId = null;
981
982
        // Parse the params out of the multipart form data
983
        // Read the incoming data from its Mime Multipart encoding
984
        logMetacat.debug("Parsing rights holder parameters from the mime multipart entity");
985
        try {
986
            collectMultipartParams();
987
988
        } catch (FileUploadException e1) {
989
            String msg = "FileUploadException: Couldn't parse the mime multipart information: " +
990
            e1.getMessage();
991
            logMetacat.debug(msg);
992
            throw new ServiceFailure("4490", msg);
993
994
        } catch (IOException e1) {
995
            String msg = "IOException: Couldn't parse the mime multipart information: " +
996
            e1.getMessage();
997
            logMetacat.debug(msg);
998
            throw new ServiceFailure("4490", msg);
999
1000
        } catch (Exception e1) {
1001
            String msg = "Exception: Couldn't parse the mime multipart information: " +
1002
            e1.getMessage();
1003
            logMetacat.debug(msg);
1004
            throw new ServiceFailure("4490", msg);
1005
1006
        }
1007
1008
        // get the serialVersion
1009
        try {
1010
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1011
            serialVersion = new Long(serialVersionStr).longValue();
1012
1013
        } catch (NumberFormatException nfe) {
1014
            String msg = "The 'serialVersion' must be provided as a positive integer and was not.";
1015
            logMetacat.error(msg);
1016
            throw new InvalidRequest("4442", msg);
1017
1018
        } catch (NullPointerException e) {
1019
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1020
            logMetacat.error(msg);
1021
            throw new InvalidRequest("4442", msg);
1022
1023
        }
1024
1025
        // get the subject userId that will become the rights holder
1026
        try {
1027
            userIdStr = multipartparams.get("userId").get(0);
1028
            userId = new Subject();
1029
            userId.setValue(userIdStr);
1030
1031
        } catch (NullPointerException e) {
1032
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1033
            logMetacat.error(msg);
1034
            throw new InvalidRequest("4442", msg);
1035
1036
        }
1037
1038
        // set the rights holder
1039
        Identifier retPid = CNodeService.getInstance(request).setRightsHolder(session, pid, userId, serialVersion);
1040
1041
        try {
1042
            OutputStream out = response.getOutputStream();
1043
            response.setStatus(200);
1044
            response.setContentType("text/xml");
1045
            TypeMarshaller.marshalTypeToOutputStream(retPid, out);
1046
1047
        } catch (IOException e) {
1048
            String msg = "Couldn't write the identifier to the response output stream: " +
1049
                e.getMessage();
1050
            logMetacat.debug(msg);
1051
            throw new ServiceFailure("4490", msg);
1052
1053 9833 tao
        } catch (MarshallingException e) {
1054 8810 leinfelder
            String msg = "Couldn't marshall the identifier to the response output stream: " +
1055
            e.getMessage();
1056
            logMetacat.debug(msg);
1057
            throw new ServiceFailure("4490", msg);
1058
1059
        }
1060
    }
1061
1062
    /**
1063
     * Processes the authorization check for given id
1064
     *
1065
     * @param id
1066
     * @return
1067
     * @throws ServiceFailure
1068
     * @throws InvalidToken
1069
     * @throws NotFound
1070
     * @throws NotAuthorized
1071
     * @throws NotImplemented
1072
     * @throws InvalidRequest
1073
     */
1074
    private boolean isAuthorized(String id) throws ServiceFailure,
1075
            InvalidToken, NotFound, NotAuthorized, NotImplemented,
1076
            InvalidRequest {
1077
        Identifier pid = new Identifier();
1078
        pid.setValue(id);
1079
        String permission = params.get("action")[0];
1080
        boolean result = CNodeService.getInstance(request).isAuthorized(
1081
                session, pid, Permission.convert(permission));
1082
        response.setStatus(200);
1083
        response.setContentType("text/xml");
1084
        return result;
1085
    }
1086
1087
    /**
1088
     * Register System Metadata without data or metadata object
1089
     *
1090
     * @param pid
1091
     *            identifier for System Metadata entry
1092 9833 tao
     * @throws MarshallingException
1093 8810 leinfelder
     * @throws FileUploadException
1094
     * @throws IOException
1095
     * @throws InvalidRequest
1096
     * @throws ServiceFailure
1097
     * @throws InvalidSystemMetadata
1098
     * @throws NotAuthorized
1099
     * @throws NotImplemented
1100
     * @throws IllegalAccessException
1101
     * @throws InstantiationException
1102
     * @throws InvalidToken
1103
     */
1104
    protected void registerSystemMetadata()
1105
            throws ServiceFailure, InvalidRequest, IOException,
1106 9833 tao
            FileUploadException, MarshallingException, NotImplemented, NotAuthorized,
1107 8810 leinfelder
            InvalidSystemMetadata, InstantiationException,
1108
            IllegalAccessException, InvalidToken {
1109
1110
    	// Read the incoming data from its Mime Multipart encoding
1111
        Map<String, File> files = collectMultipartFiles();
1112
1113
    	// get the encoded pid string from the body and make the object
1114
        String pidString = multipartparams.get("pid").get(0);
1115
        Identifier pid = new Identifier();
1116
        pid.setValue(pidString);
1117
1118
        logMetacat.debug("registerSystemMetadata: " + pid);
1119
1120
        // get the system metadata from the request
1121
        File smFile = files.get("sysmeta");
1122
        FileInputStream sysmeta = new FileInputStream(smFile);
1123
        SystemMetadata systemMetadata = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysmeta);
1124
1125
        logMetacat.debug("registering system metadata with pid " + pid.getValue());
1126
        Identifier retGuid = CNodeService.getInstance(request).registerSystemMetadata(session, pid, systemMetadata);
1127
1128
        OutputStream out = response.getOutputStream();
1129
        response.setStatus(200);
1130
        response.setContentType("text/xml");
1131
1132
        TypeMarshaller.marshalTypeToOutputStream(retGuid, out);
1133
1134
    }
1135
1136
    /**
1137
     * set the access perms on a document
1138
     *
1139 9833 tao
     * @throws MarshallingException
1140 8810 leinfelder
     * @throws InvalidRequest
1141
     * @throws NotImplemented
1142
     * @throws NotAuthorized
1143
     * @throws NotFound
1144
     * @throws ServiceFailure
1145
     * @throws InvalidToken
1146
     * @throws IllegalAccessException
1147
     * @throws InstantiationException
1148
     * @throws IOException
1149
     * @throws SAXException
1150
     * @throws ParserConfigurationException
1151
     * @throws VersionMismatch
1152
     */
1153 9833 tao
    protected void setAccess(String pid) throws MarshallingException, InvalidToken,
1154 8810 leinfelder
            ServiceFailure, NotFound, NotAuthorized, NotImplemented,
1155
            InvalidRequest, IOException, InstantiationException,
1156
            IllegalAccessException, ParserConfigurationException, SAXException, VersionMismatch {
1157
1158
        long serialVersion = 0L;
1159
        String serialVersionStr = null;
1160
1161
        // parse the accessPolicy
1162
        Map<String, File> files = collectMultipartFiles();
1163
        AccessPolicy accessPolicy = TypeMarshaller.unmarshalTypeFromFile(AccessPolicy.class, files.get("accessPolicy"));;
1164
1165
        // get the serialVersion
1166
        try {
1167
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1168
            serialVersion = new Long(serialVersionStr).longValue();
1169
1170
        } catch (NumberFormatException nfe) {
1171
            String msg = "The 'serialVersion' must be provided as a positive integer and was not.";
1172
            logMetacat.error(msg);
1173
            throw new InvalidRequest("4402", msg);
1174
1175
        } catch (NullPointerException e) {
1176
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1177
            logMetacat.error(msg);
1178
            throw new InvalidRequest("4402", msg);
1179
1180
        }
1181
1182
        Identifier id = new Identifier();
1183
        id.setValue(pid);
1184
1185
        CNodeService.getInstance(request).setAccessPolicy(session, id,
1186
                accessPolicy, serialVersion);
1187
1188
    }
1189
1190
    /**
1191
     * List the objects
1192
     *
1193
     * @throws NotImplemented
1194
     * @throws InvalidRequest
1195
     * @throws NotAuthorized
1196
     * @throws ServiceFailure
1197
     * @throws InvalidToken
1198
     * @throws NotFound
1199
     * @throws IOException
1200 9833 tao
     * @throws MarshallingException
1201 8810 leinfelder
     * @throws Exception
1202
     */
1203
    private void listObjects() throws InvalidToken, ServiceFailure,
1204
            NotAuthorized, InvalidRequest, NotImplemented, NotFound,
1205 9833 tao
            IOException, MarshallingException {
1206 8810 leinfelder
1207
        Date startTime = null;
1208
        Date endTime = null;
1209
        ObjectFormatIdentifier formatId = null;
1210
        boolean replicaStatus = true;
1211
        int start = 0;
1212
        int count = 1000;
1213
        Enumeration<String> paramlist = request.getParameterNames();
1214
        while (paramlist.hasMoreElements()) {
1215
            // parse the params and make the call
1216
            String name = paramlist.nextElement();
1217
            String[] values = request.getParameterValues(name);
1218
            String value = null;
1219
            if (values != null && values.length > 0) {
1220
            	value = values[0];
1221
            	value = EncodingUtilities.decodeString(value);
1222
            }
1223
1224
            if (name.equals("fromDate") && value != null) {
1225
                try {
1226
                    startTime = DateTimeMarshaller.deserializeDateToUTC(value);
1227
                } catch (Exception e) {
1228
                    // if we can't parse it, just don't use the startTime param
1229
                    logMetacat.warn("Could not parse fromDate: " + value);
1230
                    startTime = null;
1231
                }
1232
            } else if (name.equals("toDate") && value != null) {
1233
                try {
1234
                    endTime = DateTimeMarshaller.deserializeDateToUTC(value);
1235
                } catch (Exception e) {
1236
                    // if we can't parse it, just don't use the endTime param
1237
                    logMetacat.warn("Could not parse toDate: " + value);
1238
                    endTime = null;
1239
                }
1240
            } else if (name.equals("formatId") && value != null) {
1241
            	formatId = new ObjectFormatIdentifier();
1242
            	formatId.setValue(value);
1243
            } else if (name.equals("replicaStatus") && value != null) {
1244
                replicaStatus = Boolean.parseBoolean(value);
1245
            } else if (name.equals("start") && value != null) {
1246
                start = Integer.valueOf(value);
1247
            } else if (name.equals("count") && value != null) {
1248
                count = Integer.valueOf(value);
1249
            }
1250
        }
1251
        // make the call
1252
        logMetacat.debug("session: " + session + " fromDate: " + startTime
1253
                + " toDate: " + endTime + " formatId: " + formatId
1254
                + " replicaStatus: " + replicaStatus + " start: " + start
1255
                + " count: " + count);
1256
1257
        // get the list
1258
        ObjectList ol = CNodeService.getInstance(request).listObjects(session,
1259
                startTime, endTime, formatId, replicaStatus, start, count);
1260
1261
        // send it
1262
        OutputStream out = response.getOutputStream();
1263
        response.setStatus(200);
1264
        response.setContentType("text/xml");
1265
1266
        // style the object with a processing directive
1267
        String stylesheet = null;
1268
        try {
1269 9237 leinfelder
            stylesheet = PropertyService.getProperty("dataone.types.xsl.v1");
1270 8810 leinfelder
        } catch (PropertyNotFoundException e) {
1271
            logMetacat.warn("Could not locate DataONE types XSLT: "
1272
                    + e.getMessage());
1273
        }
1274
1275
        // Serialize and write it to the output stream
1276
        TypeMarshaller.marshalTypeToOutputStream(ol, out, stylesheet);
1277
    }
1278
1279
    /**
1280
     * Pass the request to get node replication authorization to CNodeService
1281
     *
1282
     * @param pid
1283
     *            the identifier of the object to get authorization to replicate
1284
     *
1285
     * @throws NotImplemented
1286
     * @throws NotAuthorized
1287
     * @throws InvalidToken
1288
     * @throws ServiceFailure
1289
     * @throws NotFound
1290
     * @throws InvalidRequest
1291
     */
1292
    public boolean isNodeAuthorized(String pid) throws NotImplemented,
1293
            NotAuthorized, InvalidToken, ServiceFailure, NotFound,
1294
            InvalidRequest {
1295
1296
        boolean result = false;
1297
        Subject targetNodeSubject = new Subject();
1298
        String nodeSubject = null;
1299
        String replPermission = null;
1300
1301
        // get the pid
1302
        Identifier identifier = new Identifier();
1303
        identifier.setValue(pid);
1304
1305
        // get the target node subject
1306
        try {
1307
            nodeSubject = params.get("targetNodeSubject")[0];
1308
            targetNodeSubject.setValue(nodeSubject);
1309
1310
        } catch (NullPointerException e) {
1311
            String msg = "The 'targetNodeSubject' must be provided as a parameter and was not.";
1312
            logMetacat.error(msg);
1313
            throw new InvalidRequest("4873", msg);
1314
1315
        }
1316
1317
        result = CNodeService.getInstance(request).isNodeAuthorized(session, targetNodeSubject, identifier);
1318
1319
        response.setStatus(200);
1320
        response.setContentType("text/xml");
1321
        return result;
1322
1323
    }
1324
1325
    /**
1326
     * Pass the request to set the replication policy to CNodeService
1327
     *
1328
     * @param pid
1329
     *            the identifier of the object to set the replication policy on
1330
     *
1331
     * @throws NotImplemented
1332
     * @throws NotFound
1333
     * @throws NotAuthorized
1334
     * @throws ServiceFailure
1335
     * @throws InvalidRequest
1336
     * @throws InvalidToken
1337
     * @throws IOException
1338
     * @throws InstantiationException
1339
     * @throws IllegalAccessException
1340 9833 tao
     * @throws MarshallingException
1341 8810 leinfelder
     * @throws VersionMismatch
1342
     */
1343
    public boolean setReplicationPolicy(String pid) throws NotImplemented,
1344
            NotFound, NotAuthorized, ServiceFailure, InvalidRequest,
1345
            InvalidToken, IOException, InstantiationException,
1346 9833 tao
            IllegalAccessException, MarshallingException, VersionMismatch {
1347 8810 leinfelder
1348
        boolean result = false;
1349
        long serialVersion = 0L;
1350
        String serialVersionStr = null;
1351
1352
        Identifier identifier = new Identifier();
1353
        identifier.setValue(pid);
1354
1355
        // parse the policy
1356
        Map<String, File> files = collectMultipartFiles();
1357
        ReplicationPolicy policy = TypeMarshaller.unmarshalTypeFromFile(ReplicationPolicy.class, files.get("policy"));
1358
1359
        // get the serialVersion
1360
        try {
1361
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1362
            serialVersion = new Long(serialVersionStr).longValue();
1363
1364
        } catch (NullPointerException e) {
1365
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1366
            logMetacat.error(msg);
1367
            throw new InvalidRequest("4883", msg);
1368
1369
        }
1370
        result = CNodeService.getInstance(request).setReplicationPolicy(
1371
                session, identifier, policy, serialVersion);
1372
        response.setStatus(200);
1373
        response.setContentType("text/xml");
1374
        return result;
1375
1376
    }
1377
1378
    /**
1379
     * Update the system metadata for a given pid, setting it to be obsoleted
1380
     * by the obsoletedByPid
1381
     *
1382
     * @param pid
1383
     * @return
1384
     * @throws NotImplemented
1385
     * @throws NotFound
1386
     * @throws NotAuthorized
1387
     * @throws ServiceFailure
1388
     * @throws InvalidRequest
1389
     * @throws InvalidToken
1390
     * @throws InstantiationException
1391
     * @throws IllegalAccessException
1392
     * @throws VersionMismatch
1393
     */
1394
    public boolean setObsoletedBy(String pid)
1395
        throws NotImplemented, NotFound, NotAuthorized, ServiceFailure,
1396
        InvalidRequest, InvalidToken, InstantiationException,
1397
        IllegalAccessException, VersionMismatch {
1398
1399
        boolean result = false;
1400
        long serialVersion = 0L;
1401
        String serialVersionStr = null;
1402
1403
        Identifier identifier = new Identifier();
1404
        identifier.setValue(pid);
1405
        String obsoletedByPidString = null;
1406
        Identifier obsoletedByPid = null;
1407
1408
        // Parse the params out of the multipart form data
1409
        // Read the incoming data from its Mime Multipart encoding
1410
        logMetacat.debug("Parsing rights holder parameters from the mime multipart entity");
1411
        try {
1412
            collectMultipartParams();
1413
1414
        } catch (FileUploadException e1) {
1415
            String msg = "FileUploadException: Couldn't parse the mime multipart information: " +
1416
            e1.getMessage();
1417
            logMetacat.debug(msg);
1418
            throw new ServiceFailure("4941", msg);
1419
1420
        } catch (IOException e1) {
1421
            String msg = "IOException: Couldn't parse the mime multipart information: " +
1422
            e1.getMessage();
1423
            logMetacat.debug(msg);
1424
            throw new ServiceFailure("4941", msg);
1425
1426
        } catch (Exception e1) {
1427
            String msg = "Exception: Couldn't parse the mime multipart information: " +
1428
            e1.getMessage();
1429
            logMetacat.debug(msg);
1430
            throw new ServiceFailure("4941", msg);
1431
1432
        }
1433
1434
        // get the obsoletedByPid
1435
        try {
1436
            obsoletedByPidString = multipartparams.get("obsoletedByPid").get(0);
1437
            obsoletedByPid = new Identifier();
1438
            obsoletedByPid.setValue(obsoletedByPidString);
1439
        } catch (NullPointerException e) {
1440
            String msg = "The 'obsoletedByPid' must be provided as a parameter and was not.";
1441
            logMetacat.error(msg);
1442
            throw new InvalidRequest("4883", msg);
1443
        }
1444
1445
        // get the serialVersion
1446
        try {
1447
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1448
            serialVersion = new Long(serialVersionStr).longValue();
1449
1450
        } catch (NumberFormatException nfe) {
1451
            String msg = "The 'serialVersion' must be provided as a positive integer and was not.";
1452
            logMetacat.error(msg);
1453
            throw new InvalidRequest("4942", msg);
1454
1455
        } catch (NullPointerException e) {
1456
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1457
            logMetacat.error(msg);
1458
            throw new InvalidRequest("4942", msg);
1459
1460
        }
1461
        result = CNodeService.getInstance(request).setObsoletedBy(session,
1462
            identifier, obsoletedByPid, serialVersion);
1463
        response.setStatus(200);
1464
        response.setContentType("text/xml");
1465
        return result;
1466
1467
    }
1468
1469
    /**
1470
     * Delete the replica entry with the given nodeId for the given pid
1471
     *
1472
     * @param pid
1473
     * @return
1474
     * @throws NotImplemented
1475
     * @throws NotFound
1476
     * @throws NotAuthorized
1477
     * @throws ServiceFailure
1478
     * @throws InvalidRequest
1479
     * @throws InvalidToken
1480
     * @throws InstantiationException
1481
     * @throws IllegalAccessException
1482
     * @throws VersionMismatch
1483
     */
1484
    public boolean deleteReplica(String pid)
1485
        throws NotImplemented, NotFound, NotAuthorized, ServiceFailure,
1486
        InvalidRequest, InvalidToken, InstantiationException,
1487
        IllegalAccessException, VersionMismatch {
1488
1489
        boolean result = false;
1490
        long serialVersion = 0L;
1491
        String serialVersionStr = null;
1492
1493
        Identifier identifier = new Identifier();
1494
        identifier.setValue(pid);
1495
1496
        NodeReference nodeId = null;
1497
1498
        // Parse the params out of the multipart form data
1499
        // Read the incoming data from its Mime Multipart encoding
1500
        logMetacat.debug("Parsing delete replica parameters from the mime multipart entity");
1501
        try {
1502
            collectMultipartParams();
1503
1504
        } catch (FileUploadException e1) {
1505
            String msg = "FileUploadException: Couldn't parse the mime multipart information: " +
1506
            e1.getMessage();
1507
            logMetacat.debug(msg);
1508
            throw new ServiceFailure("4951", msg);
1509
1510
        } catch (IOException e1) {
1511
            String msg = "IOException: Couldn't parse the mime multipart information: " +
1512
            e1.getMessage();
1513
            logMetacat.debug(msg);
1514
            throw new ServiceFailure("4951", msg);
1515
1516
        } catch (Exception e1) {
1517
            String msg = "Exception: Couldn't parse the mime multipart information: " +
1518
            e1.getMessage();
1519
            logMetacat.debug(msg);
1520
            throw new ServiceFailure("4951", msg);
1521
1522
        }
1523
1524
        // get the nodeId param
1525
        try {
1526
            String nodeIdString = multipartparams.get("nodeId").get(0);
1527
            nodeId = new NodeReference();
1528
            nodeId.setValue(nodeIdString);
1529
1530
        } catch (NullPointerException e) {
1531
            String msg = "The 'nodeId' must be provided as a parameter and was not.";
1532
            logMetacat.error(msg);
1533
            throw new InvalidRequest("4952", msg);
1534
        }
1535
1536
        // get the serialVersion
1537
        try {
1538
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1539
            serialVersion = new Long(serialVersionStr).longValue();
1540
1541
        } catch (NumberFormatException nfe) {
1542
            String msg = "The 'serialVersion' must be provided as a positive integer and was not.";
1543
            logMetacat.error(msg);
1544
            throw new InvalidRequest("4952", msg);
1545
1546
        } catch (NullPointerException e) {
1547
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1548
            logMetacat.error(msg);
1549
            throw new InvalidRequest("4952", msg);
1550
1551
        }
1552
        result = CNodeService.getInstance(request).deleteReplicationMetadata(
1553
                session, identifier, nodeId, serialVersion);
1554
        response.setStatus(200);
1555
        response.setContentType("text/xml");
1556
        return result;
1557
1558
    }
1559
1560
    /**
1561
     * Pass the request to set the replication status to CNodeService
1562
     *
1563
     * @param pid
1564
     *            the identifier of the object to set the replication status on
1565
     *
1566
     * @throws ServiceFailure
1567
     * @throws NotImplemented
1568
     * @throws InvalidToken
1569
     * @throws NotAuthorized
1570
     * @throws InvalidRequest
1571
     * @throws NotFound
1572 9833 tao
     * @throws MarshallingException
1573 8810 leinfelder
     * @throws IllegalAccessException
1574
     * @throws InstantiationException
1575
     * @throws IOException
1576
     */
1577
    public boolean setReplicationStatus(String pid) throws ServiceFailure,
1578
            NotImplemented, InvalidToken, NotAuthorized, InvalidRequest,
1579
            NotFound {
1580
1581
        boolean result = false;
1582
        Identifier identifier = new Identifier();
1583
        identifier.setValue(pid);
1584
        BaseException failure = null;
1585
        ReplicationStatus status = null;
1586
        String replicationStatus = null;
1587
        NodeReference targetNodeRef = null;
1588
        String targetNode = null;
1589
1590
        // Parse the params out of the multipart form data
1591
        // Read the incoming data from its Mime Multipart encoding
1592
        logMetacat.debug("Parsing ReplicaStatus from the mime multipart entity");
1593
1594
        try {
1595 9271 leinfelder
        	// parse the failure, if we have it
1596 8810 leinfelder
            Map<String, File> files = collectMultipartFiles();
1597 9271 leinfelder
            if (files.containsKey("failure")) {
1598
            	failure = ExceptionHandler.deserializeXml(new FileInputStream(files.get("failure")),
1599
                        "Replication failed for an unknown reason.");
1600
            }
1601 8810 leinfelder
1602
        } catch (Exception e2) {
1603
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1604
                e2.getMessage());
1605
1606
        }
1607
1608
        // get the replication status param
1609
        try {
1610
            replicationStatus = multipartparams.get("status").get(0);
1611
            status = ReplicationStatus.convert(replicationStatus);
1612
1613
        } catch (NullPointerException npe) {
1614
1615
            logMetacat.debug("The 'status' parameter was not found in the "
1616
                    + "multipartparams map.  Trying the params map.");
1617
1618
            try {
1619
                replicationStatus = params.get("status")[0];
1620
                status = ReplicationStatus.convert(replicationStatus
1621
                        .toLowerCase());
1622
1623
            } catch (Exception e) {
1624
                String msg = "The 'status' must be provided as a parameter and was not.";
1625
                logMetacat.error(msg);
1626
                throw new InvalidRequest("4730", msg);
1627
1628
            }
1629
1630
        }
1631
1632
        // get the target node reference param
1633
        try {
1634
            targetNode = multipartparams.get("nodeRef").get(0);
1635
            targetNodeRef = new NodeReference();
1636
            targetNodeRef.setValue(targetNode);
1637
1638
        } catch (NullPointerException e) {
1639
            logMetacat.debug("The 'nodeRef' parameter was not found in the "
1640
                    + "multipartparams map.  Trying the params map.");
1641
1642
            try {
1643
                targetNode = params.get("nodeRef")[0];
1644
                targetNodeRef = new NodeReference();
1645
                targetNodeRef.setValue(targetNode);
1646
1647
            } catch (Exception e1) {
1648
                String msg = "The 'nodeRef' must be provided as a parameter and was not.";
1649
                logMetacat.error(msg);
1650
                throw new InvalidRequest("4730", msg);
1651
1652
            }
1653
1654
        }
1655
1656
        result = CNodeService.getInstance(request).setReplicationStatus(
1657
                session, identifier, targetNodeRef, status, failure);
1658
        response.setStatus(200);
1659
        response.setContentType("text/xml");
1660
        return result;
1661
1662
    }
1663
1664
    /**
1665
     * Pass the request to update the replication metadata to CNodeService
1666
     *
1667
     * @param pid
1668
     *            the identifier of the object to update the replication
1669
     *            metadata on
1670
     *
1671
     * @throws ServiceFailure
1672
     * @throws NotImplemented
1673
     * @throws InvalidToken
1674
     * @throws NotAuthorized
1675
     * @throws InvalidRequest
1676
     * @throws NotFound
1677
     * @throws VersionMismatch
1678 9833 tao
     * @throws MarshallingException
1679 8810 leinfelder
     * @throws IOException
1680
     * @throws IllegalAccessException
1681
     * @throws InstantiationException
1682
     */
1683
    public boolean updateReplicationMetadata(String pid) throws ServiceFailure,
1684
            NotImplemented, InvalidToken, NotAuthorized, InvalidRequest,
1685 9833 tao
            NotFound, VersionMismatch, InstantiationException, IllegalAccessException, IOException, MarshallingException {
1686 8810 leinfelder
1687
        boolean result = false;
1688
        long serialVersion = 0L;
1689
        String serialVersionStr = null;
1690
        Identifier identifier = new Identifier();
1691
        identifier.setValue(pid);
1692
1693
        // parse the replica
1694
        Map<String, File> files = collectMultipartFiles();
1695
        Replica replica = TypeMarshaller.unmarshalTypeFromFile(Replica.class, files.get("replicaMetadata"));
1696
1697
        // get the serialVersion
1698
        try {
1699
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1700
            serialVersion = new Long(serialVersionStr).longValue();
1701
1702
        } catch (NullPointerException e) {
1703
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1704
            logMetacat.error(msg);
1705
            throw new InvalidRequest("4853", msg);
1706
1707
        }
1708
1709
        result = CNodeService.getInstance(request).updateReplicationMetadata(
1710
                session, identifier, replica, serialVersion);
1711
        response.setStatus(200);
1712
        response.setContentType("text/xml");
1713
        return result;
1714
1715
    }
1716
1717
}