Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *  Copyright: 2011 Regents of the University of California and the
4
 *              National Center for Ecological Analysis and Synthesis
5
 *
6
 *   '$Author: leinfelder $'
7
 *     '$Date: 2012-01-11 11:31:11 -0800 (Wed, 11 Jan 2012) $'
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;
24

    
25
import java.io.ByteArrayInputStream;
26
import java.io.File;
27
import java.io.FileInputStream;
28
import java.io.IOException;
29
import java.io.InputStream;
30
import java.io.OutputStream;
31
import java.util.Date;
32
import java.util.Enumeration;
33
import java.util.Map;
34

    
35
import javax.servlet.ServletContext;
36
import javax.servlet.http.HttpServletRequest;
37
import javax.servlet.http.HttpServletResponse;
38
import javax.xml.parsers.ParserConfigurationException;
39

    
40
import org.apache.commons.fileupload.FileUploadException;
41
import org.apache.commons.io.IOUtils;
42
import org.apache.log4j.Logger;
43
import org.dataone.client.ObjectFormatCache;
44
import org.dataone.mimemultipart.MultipartRequest;
45
import org.dataone.mimemultipart.MultipartRequestResolver;
46
import org.dataone.service.exceptions.BaseException;
47
import org.dataone.service.exceptions.IdentifierNotUnique;
48
import org.dataone.service.exceptions.InsufficientResources;
49
import org.dataone.service.exceptions.InvalidRequest;
50
import org.dataone.service.exceptions.InvalidSystemMetadata;
51
import org.dataone.service.exceptions.InvalidToken;
52
import org.dataone.service.exceptions.NotAuthorized;
53
import org.dataone.service.exceptions.NotFound;
54
import org.dataone.service.exceptions.NotImplemented;
55
import org.dataone.service.exceptions.ServiceFailure;
56
import org.dataone.service.exceptions.UnsupportedType;
57
import org.dataone.service.exceptions.VersionMismatch;
58
import org.dataone.service.types.v1.AccessPolicy;
59
import org.dataone.service.types.v1.Checksum;
60
import org.dataone.service.types.v1.ChecksumAlgorithmList;
61
import org.dataone.service.types.v1.DescribeResponse;
62
import org.dataone.service.types.v1.Event;
63
import org.dataone.service.types.v1.Identifier;
64
import org.dataone.service.types.v1.Log;
65
import org.dataone.service.types.v1.NodeReference;
66
import org.dataone.service.types.v1.ObjectFormat;
67
import org.dataone.service.types.v1.ObjectFormatIdentifier;
68
import org.dataone.service.types.v1.ObjectFormatList;
69
import org.dataone.service.types.v1.ObjectList;
70
import org.dataone.service.types.v1.ObjectLocationList;
71
import org.dataone.service.types.v1.Permission;
72
import org.dataone.service.types.v1.Replica;
73
import org.dataone.service.types.v1.ReplicationPolicy;
74
import org.dataone.service.types.v1.ReplicationStatus;
75
import org.dataone.service.types.v1.Subject;
76
import org.dataone.service.types.v1.SystemMetadata;
77
import org.dataone.service.util.Constants;
78
import org.dataone.service.util.DateTimeMarshaller;
79
import org.dataone.service.util.TypeMarshaller;
80
import org.jibx.runtime.JiBXException;
81
import org.xml.sax.SAXException;
82

    
83
import edu.ucsb.nceas.metacat.dataone.CNodeService;
84
import edu.ucsb.nceas.metacat.dataone.MNodeService;
85
import edu.ucsb.nceas.metacat.properties.PropertyService;
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
            // get the resource
149
            String resource = request.getPathInfo();
150
            resource = resource.substring(resource.indexOf("/") + 1);
151

    
152
            // for the rest of the resouce
153
            String extra = null;
154

    
155
            logMetacat.debug("handling verb " + httpVerb
156
                    + " request with resource '" + resource + "'");
157
            boolean status = false;
158

    
159
            if (resource != null) {
160

    
161
                if (resource.startsWith(RESOURCE_ACCESS_RULES)
162
                        && httpVerb == PUT) {
163
                    logMetacat.debug("Setting access policy");
164
                    // after the command
165
                    extra = parseTrailing(resource, RESOURCE_ACCESS_RULES);
166
                    setAccess(extra);
167
                    status = true;
168
                    logMetacat.debug("done setting access");
169

    
170
                } else if (resource.startsWith(RESOURCE_META)) {
171
                    logMetacat.debug("Using resource: " + RESOURCE_META);
172

    
173
                    // after the command
174
                    extra = parseTrailing(resource, RESOURCE_META);
175

    
176
                    // get
177
                    if (httpVerb == GET) {
178
                        getSystemMetadataObject(extra);
179
                        status = true;
180
                    }
181
                    // post to register system metadata
182
                    if (httpVerb == POST) {
183
                        registerSystemMetadata(extra);
184
                        status = true;
185
                    }
186

    
187
                } else if (resource.startsWith(RESOURCE_RESERVE)) {
188
                    // reserve the ID (in params)
189
                    if (httpVerb == POST) {
190
                        reserve();
191
                        status = true;
192
                    }
193
                } else if (resource.startsWith(RESOURCE_RESOLVE)) {
194

    
195
                    // after the command
196
                    extra = parseTrailing(resource, RESOURCE_RESOLVE);
197

    
198
                    // resolve the object location
199
                    if (httpVerb == GET) {
200
                        resolve(extra);
201
                        status = true;
202
                    }
203
                } else if (resource.startsWith(RESOURCE_OWNER)) {
204

    
205
                    // after the command
206
                    extra = parseTrailing(resource, RESOURCE_OWNER);
207

    
208
                    // set the owner
209
                    if (httpVerb == PUT) {
210
                        owner(extra);
211
                        status = true;
212
                    }
213
                } else if (resource.startsWith(RESOURCE_IS_AUTHORIZED)) {
214

    
215
                    // after the command
216
                    extra = parseTrailing(resource, RESOURCE_IS_AUTHORIZED);
217

    
218
                    // authorized?
219
                    if (httpVerb == GET) {
220
                        isAuthorized(extra);
221
                        status = true;
222
                    }
223
                } else if (resource.startsWith(RESOURCE_OBJECTS)) {
224
                    logMetacat.debug("Using resource 'object'");
225
                    logMetacat
226
                            .debug("D1 Rest: Starting resource processing...");
227

    
228
                    // after the command
229
                    extra = parseTrailing(resource, RESOURCE_OBJECTS);
230

    
231
                    logMetacat.debug("objectId: " + extra);
232
                    logMetacat.debug("verb:" + httpVerb);
233

    
234
                    if (httpVerb == GET) {
235
                        if (extra != null) {
236
                            getObject(extra);
237
                        } else {
238
                            listObjects();
239
                        }
240
                        status = true;
241
                    } else if (httpVerb == POST) {
242
                        putObject(extra, FUNCTION_NAME_INSERT);
243
                        status = true;
244
                    } else if (httpVerb == HEAD) {
245
                        describeObject(extra);
246
                        status = true;
247
                    }
248

    
249
                } else if (resource.startsWith(RESOURCE_FORMATS)) {
250
                    logMetacat.debug("Using resource: " + RESOURCE_FORMATS);
251

    
252
                    // after the command
253
                    extra = parseTrailing(resource, RESOURCE_FORMATS);
254

    
255
                    // handle each verb
256
                    if (httpVerb == GET) {
257
                        if (extra == null) {
258
                            // list the formats collection
259
                            listFormats();
260
                        } else {
261
                            // get the specified format
262
                            getFormat(extra);
263
                        }
264
                        status = true;
265
                    }
266

    
267
                } else if (resource.startsWith(RESOURCE_LOG)) {
268
                    logMetacat.debug("Using resource: " + RESOURCE_LOG);
269
                    // handle log events
270
                    if (httpVerb == GET) {
271
                        getLog();
272
                        status = true;
273
                    }
274

    
275
                } else if (resource.startsWith(RESOURCE_CHECKSUM)) {
276
                    logMetacat.debug("Using resource: " + RESOURCE_CHECKSUM);
277

    
278
                    // after the command
279
                    extra = parseTrailing(resource, RESOURCE_CHECKSUM);
280

    
281
                    // handle checksum requests
282
                    if (httpVerb == GET) {
283

    
284
                        checksum(extra);
285
                        status = true;
286

    
287
                    }
288

    
289
                } else if (resource.startsWith(RESOURCE_REPLICATION_POLICY)
290
                        && httpVerb == PUT) {
291

    
292
                    logMetacat.debug("Using resource: "
293
                            + RESOURCE_REPLICATION_POLICY);
294
                    // get the trailing pid
295
                    extra = parseTrailing(resource, RESOURCE_REPLICATION_POLICY);
296
                    setReplicationPolicy(extra);
297
                    status = true;
298

    
299
                } else if (resource.startsWith(RESOURCE_REPLICATION_META)
300
                        && httpVerb == PUT) {
301

    
302
                    logMetacat.debug("Using resource: "
303
                            + RESOURCE_REPLICATION_META);
304
                    // get the trailing pid
305
                    extra = parseTrailing(resource, RESOURCE_REPLICATION_META);
306
                    updateReplicationMetadata(extra);
307
                    status = true;
308

    
309
                } else if (resource.startsWith(RESOURCE_REPLICATION_NOTIFY)
310
                        && httpVerb == PUT) {
311

    
312
                    logMetacat.debug("Using resource: "
313
                            + RESOURCE_REPLICATION_NOTIFY);
314
                    // get the trailing pid
315
                    extra = parseTrailing(resource, RESOURCE_REPLICATION_NOTIFY);
316
                    setReplicationStatus(extra);
317
                    status = true;
318

    
319
                } else if (resource.startsWith(RESOURCE_REPLICATION_AUTHORIZED)
320
                        && httpVerb == GET) {
321

    
322
                    logMetacat.debug("Using resource: "
323
                            + RESOURCE_REPLICATION_AUTHORIZED);
324
                    // get the trailing pid
325
                    extra = parseTrailing(resource,
326
                            RESOURCE_REPLICATION_AUTHORIZED);
327
                    isNodeAuthorized(extra);
328
                    status = true;
329

    
330
                } else if (resource.startsWith(Constants.RESOURCE_MONITOR_PING)) {
331
                    if (httpVerb == GET) {
332
                    	// after the command
333
                        extra = parseTrailing(resource, Constants.RESOURCE_MONITOR_PING);
334
                        
335
                        logMetacat.debug("processing ping request");
336
                        Date result = CNodeService.getInstance(request).ping();
337
                        // TODO: send to output	
338
                        status = true;
339
                    }
340
                } else if (resource.startsWith(Constants.RESOURCE_CHECKSUM)) {
341
                    if (httpVerb == GET) {
342
                        listChecksumAlgorithms();
343
                        status = true;
344
                    }
345
                }
346

    
347
                if (!status) {
348
                    throw new ServiceFailure("0000", "Unknown error, status = "
349
                            + status);
350
                }
351
            } else {
352
                throw new InvalidRequest("0000", "No resource matched for "
353
                        + resource);
354
            }
355
        } catch (BaseException be) {
356
            // report Exceptions as clearly and generically as possible
357
            OutputStream out = null;
358
            try {
359
                out = response.getOutputStream();
360
            } catch (IOException ioe) {
361
                logMetacat.error("Could not get output stream from response",
362
                        ioe);
363
            }
364
            serializeException(be, out);
365
        } catch (Exception e) {
366
            // report Exceptions as clearly and generically as possible
367
            logMetacat.error(e.getClass() + ": " + e.getMessage(), e);
368
            OutputStream out = null;
369
            try {
370
                out = response.getOutputStream();
371
            } catch (IOException ioe) {
372
                logMetacat.error("Could not get output stream from response",
373
                        ioe);
374
            }
375
            ServiceFailure se = new ServiceFailure("0000", e.getMessage());
376
            serializeException(se, out);
377
        }
378
    }
379

    
380
    /**
381
     * Get the checksum for the given guid
382
     * 
383
     * @param guid
384
     * @throws NotImplemented
385
     * @throws InvalidRequest
386
     * @throws NotFound
387
     * @throws NotAuthorized
388
     * @throws ServiceFailure
389
     * @throws InvalidToken
390
     * @throws IOException
391
     * @throws JiBXException
392
     */
393
    private void checksum(String guid) throws InvalidToken, ServiceFailure,
394
            NotAuthorized, NotFound, InvalidRequest, NotImplemented,
395
            JiBXException, IOException {
396
        Identifier guidid = new Identifier();
397
        guidid.setValue(guid);
398
        logMetacat.debug("getting checksum for object " + guid);
399
        Checksum c = CNodeService.getInstance(request).getChecksum(session,
400
                guidid);
401
        logMetacat.debug("got checksum " + c.getValue());
402
        response.setStatus(200);
403
        logMetacat.debug("serializing response");
404
        TypeMarshaller.marshalTypeToOutputStream(c, response.getOutputStream());
405
        logMetacat.debug("done serializing response.");
406

    
407
    }
408

    
409
    /**
410
     * get the logs based on passed params. Available params are token,
411
     * fromDate, toDate, event. See
412
     * http://mule1.dataone.org/ArchitectureDocs/mn_api_crud
413
     * .html#MN_crud.getLogRecords for more info
414
     * 
415
     * @throws NotImplemented
416
     * @throws InvalidRequest
417
     * @throws NotAuthorized
418
     * @throws ServiceFailure
419
     * @throws InvalidToken
420
     * @throws IOException
421
     * @throws JiBXException
422
     */
423
    private void getLog() throws InvalidToken, ServiceFailure, NotAuthorized,
424
            InvalidRequest, NotImplemented, IOException, JiBXException {
425

    
426
        Date fromDate = null;
427
        Date toDate = null;
428
        Event event = null;
429
        Integer start = null;
430
        Integer count = null;
431

    
432
        try {
433
            String fromDateS = params.get("fromDate")[0];
434
            logMetacat.debug("param fromDateS: " + fromDateS);
435
            fromDate = DateTimeMarshaller.deserializeDateToUTC(fromDateS);
436
        } catch (Exception e) {
437
            logMetacat.warn("Could not parse fromDate: " + e.getMessage());
438
        }
439
        try {
440
            String toDateS = params.get("toDate")[0];
441
            logMetacat.debug("param toDateS: " + toDateS);
442
            toDate = DateTimeMarshaller.deserializeDateToUTC(toDateS);
443
        } catch (Exception e) {
444
            logMetacat.warn("Could not parse toDate: " + e.getMessage());
445
        }
446
        try {
447
            String eventS = params.get("event")[0];
448
            event = Event.convert(eventS);
449
        } catch (Exception e) {
450
            logMetacat.warn("Could not parse event: " + e.getMessage());
451
        }
452
        logMetacat.debug("fromDate: " + fromDate + " toDate: " + toDate);
453

    
454
        try {
455
            start = Integer.parseInt(params.get("start")[0]);
456
        } catch (Exception e) {
457
            logMetacat.warn("Could not parse start: " + e.getMessage());
458
        }
459
        try {
460
            count = Integer.parseInt(params.get("count")[0]);
461
        } catch (Exception e) {
462
            logMetacat.warn("Could not parse count: " + e.getMessage());
463
        }
464

    
465
        logMetacat.debug("calling getLogRecords");
466
        Log log = CNodeService.getInstance(request).getLogRecords(session,
467
                fromDate, toDate, event, start, count);
468

    
469
        OutputStream out = response.getOutputStream();
470
        response.setStatus(200);
471
        response.setContentType("text/xml");
472

    
473
        TypeMarshaller.marshalTypeToOutputStream(log, out);
474

    
475
    }
476

    
477
    /**
478
     * Implements REST version of DataONE CRUD API --> get
479
     * 
480
     * @param guid
481
     *            ID of data object to be read
482
     * @throws NotImplemented
483
     * @throws InvalidRequest
484
     * @throws NotFound
485
     * @throws NotAuthorized
486
     * @throws ServiceFailure
487
     * @throws InvalidToken
488
     * @throws IOException
489
     */
490
    protected void getObject(String guid) throws InvalidToken, ServiceFailure,
491
            NotAuthorized, NotFound, InvalidRequest, NotImplemented,
492
            IOException {
493

    
494
        Identifier id = new Identifier();
495
        id.setValue(guid);
496

    
497
        SystemMetadata sm = CNodeService.getInstance(request)
498
                .getSystemMetadata(session, id);
499

    
500
        // set the content type
501
        if (sm.getFormatId()
502
                .getValue()
503
                .trim()
504
                .equals(ObjectFormatCache.getInstance().getFormat("text/csv")
505
                        .getFormatId().getValue())) {
506
            response.setContentType("text/csv");
507
            response.setHeader("Content-Disposition",
508
                    "inline; filename=" + id.getValue() + ".csv");
509
        } else if (sm
510
                .getFormatId()
511
                .getValue()
512
                .trim()
513
                .equals(ObjectFormatCache.getInstance().getFormat("text/plain")
514
                        .getFormatId().getValue())) {
515
            response.setContentType("text/plain");
516
            response.setHeader("Content-Disposition",
517
                    "inline; filename=" + id.getValue() + ".txt");
518
        } else if (sm
519
                .getFormatId()
520
                .getValue()
521
                .trim()
522
                .equals(ObjectFormatCache.getInstance()
523
                        .getFormat("application/octet-stream").getFormatId()
524
                        .getValue())) {
525
            response.setContentType("application/octet-stream");
526
        } else {
527
            response.setContentType("text/xml");
528
            response.setHeader("Content-Disposition",
529
                    "inline; filename=" + id.getValue() + ".xml");
530
        }
531

    
532
        InputStream data = CNodeService.getInstance(request).get(session, id);
533

    
534
        OutputStream out = response.getOutputStream();
535
        response.setStatus(200);
536
        IOUtils.copyLarge(data, out);
537

    
538
    }
539

    
540
    /**
541
     * Implements REST version of DataONE CRUD API --> getSystemMetadata
542
     * 
543
     * @param guid
544
     *            ID of data object to be read
545
     * @throws NotImplemented
546
     * @throws InvalidRequest
547
     * @throws NotFound
548
     * @throws NotAuthorized
549
     * @throws ServiceFailure
550
     * @throws InvalidToken
551
     * @throws IOException
552
     * @throws JiBXException
553
     */
554
    protected void getSystemMetadataObject(String guid) throws InvalidToken,
555
            ServiceFailure, NotAuthorized, NotFound, InvalidRequest,
556
            NotImplemented, IOException, JiBXException {
557

    
558
        Identifier id = new Identifier();
559
        id.setValue(guid);
560
        SystemMetadata sysmeta = CNodeService.getInstance(request)
561
                .getSystemMetadata(session, id);
562

    
563
        response.setContentType("text/xml");
564
        response.setStatus(200);
565
        OutputStream out = response.getOutputStream();
566

    
567
        // Serialize and write it to the output stream
568
        TypeMarshaller.marshalTypeToOutputStream(sysmeta, out);
569
    }
570

    
571
    /**
572
     * Earthgrid API > Put Service >Put Function : calls MetacatHandler >
573
     * handleInsertOrUpdateAction
574
     * 
575
     * @param guid
576
     *            - ID of data object to be inserted or updated. If action is
577
     *            update, the pid is the existing pid. If insert, the pid is the
578
     *            new one
579
     * @throws InvalidRequest
580
     * @throws ServiceFailure
581
     * @throws IdentifierNotUnique
582
     * @throws JiBXException
583
     * @throws NotImplemented
584
     * @throws InvalidSystemMetadata
585
     * @throws InsufficientResources
586
     * @throws UnsupportedType
587
     * @throws NotAuthorized
588
     * @throws InvalidToken
589
     * @throws IOException
590
     * @throws IllegalAccessException
591
     * @throws InstantiationException
592
     */
593
    protected void putObject(String pid, String action) throws ServiceFailure,
594
            InvalidRequest, IdentifierNotUnique, JiBXException, InvalidToken,
595
            NotAuthorized, UnsupportedType, InsufficientResources,
596
            InvalidSystemMetadata, NotImplemented, IOException,
597
            InstantiationException, IllegalAccessException {
598
        logMetacat.debug("Entering putObject: " + pid + "/" + action);
599

    
600
        // Read the incoming data from its Mime Multipart encoding
601
        Map<String, File> files = collectMultipartFiles();
602
        InputStream object = null;
603
        InputStream sysmeta = null;
604

    
605
        File smFile = files.get("sysmeta");
606
        sysmeta = new FileInputStream(smFile);
607
        File objFile = files.get("object");
608
        object = new FileInputStream(objFile);
609

    
610
        if (action.equals(FUNCTION_NAME_INSERT)) { // handle inserts
611

    
612
            logMetacat.debug("Commence creation...");
613
            SystemMetadata smd = TypeMarshaller.unmarshalTypeFromStream(
614
                    SystemMetadata.class, sysmeta);
615

    
616
            Identifier id = new Identifier();
617
            id.setValue(pid);
618
            logMetacat.debug("creating object with pid " + id.getValue());
619
            Identifier rId = CNodeService.getInstance(request).create(session,
620
                    id, object, smd);
621

    
622
            OutputStream out = response.getOutputStream();
623
            response.setStatus(200);
624
            response.setContentType("text/xml");
625

    
626
            TypeMarshaller.marshalTypeToOutputStream(rId, out);
627

    
628
        } else {
629
            throw new InvalidRequest("1000", "Operation must be create.");
630
        }
631
    }
632

    
633
    /**
634
     * List the object formats registered with the system
635
     * 
636
     * @throws NotImplemented
637
     * @throws InsufficientResources
638
     * @throws NotFound
639
     * @throws ServiceFailure
640
     * @throws InvalidRequest
641
     * @throws IOException
642
     * @throws JiBXException
643
     */
644
    private void listFormats() throws InvalidRequest, ServiceFailure, NotFound,
645
            InsufficientResources, NotImplemented, IOException, JiBXException {
646
        logMetacat.debug("Entering listFormats()");
647

    
648
        ObjectFormatList objectFormatList = CNodeService.getInstance(request)
649
                .listFormats();
650
        // get the response output stream
651
        OutputStream out = response.getOutputStream();
652
        response.setStatus(200);
653
        response.setContentType("text/xml");
654

    
655
        // style the object with a processing directive
656
        String stylesheet = null;
657
        try {
658
            stylesheet = PropertyService.getProperty("dataone.types.xsl");
659
        } catch (PropertyNotFoundException e) {
660
            logMetacat.warn("Could not locate DataONE types XSLT: "
661
                    + e.getMessage());
662
        }
663

    
664
        TypeMarshaller.marshalTypeToOutputStream(objectFormatList, out,
665
                stylesheet);
666

    
667
    }
668
    
669
    private void listChecksumAlgorithms() throws IOException, ServiceFailure,
670
			NotImplemented, JiBXException {
671
		logMetacat.debug("Entering listFormats()");
672

    
673
		ChecksumAlgorithmList result = CNodeService.getInstance(request).listChecksumAlgorithms();
674

    
675
		// get the response output stream
676
		OutputStream out = response.getOutputStream();
677
		response.setStatus(200);
678
		response.setContentType("text/xml");
679

    
680
		// style the object with a processing directive
681
		String stylesheet = null;
682
		try {
683
			stylesheet = PropertyService.getProperty("dataone.types.xsl");
684
		} catch (PropertyNotFoundException e) {
685
			logMetacat.warn("Could not locate DataONE types XSLT: "
686
					+ e.getMessage());
687
		}
688

    
689
		TypeMarshaller.marshalTypeToOutputStream(result, out, stylesheet);
690

    
691
	}
692
    
693
    /**
694
     * http://mule1.dataone.org/ArchitectureDocs-current/apis/CN_APIs.html#CNRead.describe
695
     * @param pid
696
     * @throws InvalidToken
697
     * @throws ServiceFailure
698
     * @throws NotAuthorized
699
     * @throws NotFound
700
     * @throws NotImplemented
701
     * @throws InvalidRequest
702
     */
703
    private void describeObject(String pid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, InvalidRequest
704
    {
705
        response.setStatus(200);
706
        response.setContentType("text/xml");
707
        
708
        Identifier id = new Identifier();
709
        id.setValue(pid);
710

    
711
        DescribeResponse dr = CNodeService.getInstance(request).describe(session, id);
712
        //response.addHeader("pid", pid);
713
        response.addHeader("DataONE-Checksum", dr.getDataONE_Checksum().getAlgorithm() + "," + dr.getDataONE_Checksum().getValue());
714
        response.addHeader("Content-Length", dr.getContent_Length() + "");
715
        response.addHeader("Last-Modified", DateTimeMarshaller.serializeDateToUTC(dr.getLast_Modified()));
716
        response.addHeader("DataONE-ObjectFormat", dr.getDataONE_ObjectFormatIdentifier().getValue());
717
        response.addHeader("DataONE-SerialVersion", dr.getSerialVersion().toString());
718

    
719
    }
720

    
721
    /**
722
     * Return the requested object format
723
     * 
724
     * @param fmtidStr
725
     *            the requested format identifier as a string
726
     * @throws NotImplemented
727
     * @throws InsufficientResources
728
     * @throws NotFound
729
     * @throws ServiceFailure
730
     * @throws InvalidRequest
731
     * @throws IOException
732
     * @throws JiBXException
733
     */
734
    private void getFormat(String fmtidStr) throws InvalidRequest,
735
            ServiceFailure, NotFound, InsufficientResources, NotImplemented,
736
            IOException, JiBXException {
737
        logMetacat.debug("Entering listFormats()");
738

    
739
        ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
740
        fmtid.setValue(fmtidStr);
741

    
742
        // get the specified object format
743
        ObjectFormat objectFormat = CNodeService.getInstance(request)
744
                .getFormat(fmtid);
745

    
746
        OutputStream out = response.getOutputStream();
747
        response.setStatus(200);
748
        response.setContentType("text/xml");
749

    
750
        TypeMarshaller.marshalTypeToOutputStream(objectFormat, out);
751

    
752
    }
753

    
754
    /**
755
     * Reserve the given Identifier
756
     * 
757
     * @throws InvalidToken
758
     * @throws ServiceFailure
759
     * @throws NotAuthorized
760
     * @throws IdentifierNotUnique
761
     * @throws NotImplemented
762
     * @throws InvalidRequest
763
     * @throws IOException
764
     * @throws JiBXException
765
     */
766
    private void reserve() throws InvalidToken, ServiceFailure, NotAuthorized,
767
            IdentifierNotUnique, NotImplemented, InvalidRequest, IOException,
768
            JiBXException {
769
        Identifier pid = null;
770
        String scope = null;
771
        String format = null;
772
        // gather the params
773
        try {
774
            String id = params.get("pid")[0];
775
            pid = new Identifier();
776
            pid.setValue(id);
777
        } catch (Exception e) {
778
            logMetacat.warn("pid not specified");
779
        }
780
        try {
781
            scope = params.get("scope")[0];
782
        } catch (Exception e) {
783
            logMetacat.warn("pid not specified");
784
        }
785
        try {
786
            format = params.get("format")[0];
787
        } catch (Exception e) {
788
            logMetacat.warn("pid not specified");
789
        }
790
        // call the implementation
791
        Identifier resultPid = CNodeService.getInstance(request)
792
                .reserveIdentifier(session, pid);
793
        OutputStream out = response.getOutputStream();
794
        response.setStatus(200);
795
        response.setContentType("text/xml");
796
        // send back the reserved pid
797
        TypeMarshaller.marshalTypeToOutputStream(resultPid, out);
798
    }
799

    
800
    /**
801
     * 
802
     * @param id
803
     * @throws InvalidRequest
804
     * @throws InvalidToken
805
     * @throws ServiceFailure
806
     * @throws NotAuthorized
807
     * @throws NotFound
808
     * @throws NotImplemented
809
     * @throws IOException
810
     * @throws JiBXException
811
     */
812
    private void resolve(String id) throws InvalidRequest, InvalidToken,
813
            ServiceFailure, NotAuthorized, NotFound, NotImplemented,
814
            IOException, JiBXException {
815
        Identifier pid = new Identifier();
816
        pid.setValue(id);
817
        ObjectLocationList locationList = CNodeService.getInstance(request)
818
                .resolve(session, pid);
819
        OutputStream out = response.getOutputStream();
820
        response.setStatus(200);
821
        response.setContentType("text/xml");
822
        TypeMarshaller.marshalTypeToOutputStream(locationList, out);
823

    
824
    }
825

    
826
    /**
827
     * Set the owner of a resource
828
     * 
829
     * @param id
830
     * @throws JiBXException
831
     * @throws InvalidToken
832
     * @throws ServiceFailure
833
     * @throws NotFound
834
     * @throws NotAuthorized
835
     * @throws NotImplemented
836
     * @throws InvalidRequest
837
     * @throws IOException
838
     * @throws IllegalAccessException
839
     * @throws InstantiationException
840
     * @throws VersionMismatch 
841
     */
842
    private void owner(String id) throws JiBXException, InvalidToken,
843
            ServiceFailure, NotFound, NotAuthorized, NotImplemented,
844
            InvalidRequest, IOException, InstantiationException,
845
            IllegalAccessException, VersionMismatch {
846

    
847
        Identifier pid = new Identifier();
848
        pid.setValue(id);
849

    
850
        long serialVersion = 0L;
851
        String serialVersionStr = null;
852

    
853
        // get the serialVersion
854
        try {
855
            serialVersionStr = params.get("serialVersion")[0];
856
            serialVersion = new Long(serialVersionStr).longValue();
857

    
858
        } catch (NullPointerException e) {
859
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
860
            logMetacat.error(msg);
861
            throw new InvalidRequest("4442", msg);
862

    
863
        }
864

    
865
        // get the subject
866
        String subjectStr = params.get("subject")[0];
867
        Subject subject = TypeMarshaller.unmarshalTypeFromStream(Subject.class,
868
                new ByteArrayInputStream(subjectStr.getBytes("UTF-8")));
869

    
870
        Identifier retPid = CNodeService.getInstance(request).setRightsHolder(session, pid, subject, serialVersion);
871
        OutputStream out = response.getOutputStream();
872
        response.setStatus(200);
873
        response.setContentType("text/xml");
874
        TypeMarshaller.marshalTypeToOutputStream(retPid, out);
875
    }
876

    
877
    /**
878
     * Processes the authorization check for given id
879
     * 
880
     * @param id
881
     * @return
882
     * @throws ServiceFailure
883
     * @throws InvalidToken
884
     * @throws NotFound
885
     * @throws NotAuthorized
886
     * @throws NotImplemented
887
     * @throws InvalidRequest
888
     */
889
    private boolean isAuthorized(String id) throws ServiceFailure,
890
            InvalidToken, NotFound, NotAuthorized, NotImplemented,
891
            InvalidRequest {
892
        Identifier pid = new Identifier();
893
        pid.setValue(id);
894
        String permission = params.get("action")[0];
895
        boolean result = CNodeService.getInstance(request).isAuthorized(
896
                session, pid, Permission.convert(permission));
897
        response.setStatus(200);
898
        response.setContentType("text/xml");
899
        return result;
900
    }
901

    
902
    /**
903
     * Register System Metadata without data or metadata object
904
     * 
905
     * @param pid
906
     *            identifier for System Metadata entry
907
     * @throws JiBXException
908
     * @throws FileUploadException
909
     * @throws IOException
910
     * @throws InvalidRequest
911
     * @throws ServiceFailure
912
     * @throws InvalidSystemMetadata
913
     * @throws NotAuthorized
914
     * @throws NotImplemented
915
     * @throws IllegalAccessException
916
     * @throws InstantiationException
917
     */
918
    protected void registerSystemMetadata(String pid)
919
            throws ServiceFailure, InvalidRequest, IOException,
920
            FileUploadException, JiBXException, NotImplemented, NotAuthorized,
921
            InvalidSystemMetadata, InstantiationException,
922
            IllegalAccessException {
923
        logMetacat.debug("Entering registerSystemMetadata: " + pid);
924

    
925
        // get the system metadata from the request
926
        SystemMetadata systemMetadata = collectSystemMetadata();
927

    
928
        Identifier guid = new Identifier();
929
        guid.setValue(pid);
930
        logMetacat.debug("registering system metadata with pid "
931
                + guid.getValue());
932
        Identifier retGuid = CNodeService.getInstance(request)
933
                .registerSystemMetadata(session, guid, systemMetadata);
934

    
935
        OutputStream out = response.getOutputStream();
936
        response.setStatus(200);
937
        response.setContentType("text/xml");
938
        
939
        TypeMarshaller.marshalTypeToOutputStream(retGuid, out);
940

    
941
    }
942

    
943
    /**
944
     * set the access perms on a document
945
     * 
946
     * @throws JiBXException
947
     * @throws InvalidRequest
948
     * @throws NotImplemented
949
     * @throws NotAuthorized
950
     * @throws NotFound
951
     * @throws ServiceFailure
952
     * @throws InvalidToken
953
     * @throws IllegalAccessException
954
     * @throws InstantiationException
955
     * @throws IOException
956
     * @throws SAXException
957
     * @throws ParserConfigurationException
958
     * @throws VersionMismatch 
959
     */
960
    protected void setAccess(String pid) throws JiBXException, InvalidToken,
961
            ServiceFailure, NotFound, NotAuthorized, NotImplemented,
962
            InvalidRequest, IOException, InstantiationException,
963
            IllegalAccessException, ParserConfigurationException, SAXException, VersionMismatch {
964

    
965
        long serialVersion = 0L;
966
        String serialVersionStr = null;
967

    
968
        // get the serialVersion
969
        try {
970
            serialVersionStr = params.get("serialVersion")[0];
971
            serialVersion = new Long(serialVersionStr).longValue();
972

    
973
        } catch (NullPointerException e) {
974
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
975
            logMetacat.error(msg);
976
            throw new InvalidRequest("4402", msg);
977

    
978
        }
979

    
980
        Identifier id = new Identifier();
981
        id.setValue(pid);
982

    
983
        AccessPolicy accessPolicy = collectAccessPolicy();
984
        CNodeService.getInstance(request).setAccessPolicy(session, id,
985
                accessPolicy, serialVersion);
986

    
987
    }
988

    
989
    /**
990
     * List the objects
991
     * 
992
     * @throws NotImplemented
993
     * @throws InvalidRequest
994
     * @throws NotAuthorized
995
     * @throws ServiceFailure
996
     * @throws InvalidToken
997
     * @throws NotFound
998
     * @throws IOException
999
     * @throws JiBXException
1000
     * @throws Exception
1001
     */
1002
    private void listObjects() throws InvalidToken, ServiceFailure,
1003
            NotAuthorized, InvalidRequest, NotImplemented, NotFound,
1004
            IOException, JiBXException {
1005

    
1006
        Date startTime = null;
1007
        Date endTime = null;
1008
        ObjectFormat objectFormat = null;
1009
        boolean replicaStatus = false;
1010
        int start = 0;
1011
        int count = -1;
1012
        Enumeration<String> paramlist = request.getParameterNames();
1013
        while (paramlist.hasMoreElements()) {
1014
            // parse the params and make the call
1015
            String name = paramlist.nextElement();
1016
            String[] value = request.getParameterValues(name);
1017

    
1018
            if (name.equals("startTime") && value != null) {
1019
                try {
1020
                    startTime = DateTimeMarshaller
1021
                            .deserializeDateToUTC(value[0]);
1022
                } catch (Exception e) {
1023
                    // if we can't parse it, just don't use the startTime param
1024
                    logMetacat.warn("Could not parse startTime: " + value[0]);
1025
                    startTime = null;
1026
                }
1027
            } else if (name.equals("endTime") && value != null) {
1028
                try {
1029
                    endTime = DateTimeMarshaller.deserializeDateToUTC(value[0]);
1030
                } catch (Exception e) {
1031
                    // if we can't parse it, just don't use the endTime param
1032
                    logMetacat.warn("Could not parse endTime: " + value[0]);
1033
                    endTime = null;
1034
                }
1035
            } else if (name.equals("objectFormat") && value != null) {
1036
                objectFormat = ObjectFormatCache.getInstance().getFormat(
1037
                        value[0]);
1038
            } else if (name.equals("replicaStatus") && value != null) {
1039
                replicaStatus = Boolean.parseBoolean(value[0]);
1040
            } else if (name.equals("start") && value != null) {
1041
                start = Integer.valueOf(value[0]);
1042
            } else if (name.equals("count") && value != null) {
1043
                count = Integer.valueOf(value[0]);
1044
            }
1045
        }
1046
        // make the call
1047
        logMetacat.debug("session: " + session + " startTime: " + startTime
1048
                + " endtime: " + endTime + " objectFormat: " + objectFormat
1049
                + " replicaStatus: " + replicaStatus + " start: " + start
1050
                + " count: " + count);
1051

    
1052
        ObjectFormatIdentifier fmtid = null;
1053
        if (objectFormat != null) {
1054
            fmtid = objectFormat.getFormatId();
1055
        }
1056

    
1057
        // get the list
1058
        ObjectList ol = CNodeService.getInstance(request).listObjects(session,
1059
                startTime, endTime, fmtid, replicaStatus, start, count);
1060

    
1061
        // send it
1062
        OutputStream out = response.getOutputStream();
1063
        response.setStatus(200);
1064
        response.setContentType("text/xml");
1065

    
1066
        // style the object with a processing directive
1067
        String stylesheet = null;
1068
        try {
1069
            stylesheet = PropertyService.getProperty("dataone.types.xsl");
1070
        } catch (PropertyNotFoundException e) {
1071
            logMetacat.warn("Could not locate DataONE types XSLT: "
1072
                    + e.getMessage());
1073
        }
1074

    
1075
        // Serialize and write it to the output stream
1076
        TypeMarshaller.marshalTypeToOutputStream(ol, out, stylesheet);
1077
    }
1078

    
1079
    /**
1080
     * Pass the request to get node replication authorization to CNodeService
1081
     * 
1082
     * @param pid
1083
     *            the identifier of the object to get authorization to replicate
1084
     * 
1085
     * @throws NotImplemented
1086
     * @throws NotAuthorized
1087
     * @throws InvalidToken
1088
     * @throws ServiceFailure
1089
     * @throws NotFound
1090
     * @throws InvalidRequest
1091
     */
1092
    public boolean isNodeAuthorized(String pid) throws NotImplemented,
1093
            NotAuthorized, InvalidToken, ServiceFailure, NotFound,
1094
            InvalidRequest {
1095

    
1096
        boolean result = false;
1097
        Subject targetNodeSubject = new Subject();
1098
        String nodeSubject = null;
1099
        String replPermission = null;
1100

    
1101
        // get the pid
1102
        Identifier identifier = new Identifier();
1103
        identifier.setValue(pid);
1104

    
1105
        // get the target node subject
1106
        try {
1107
            nodeSubject = params.get("targetNodeSubject")[0];
1108
            targetNodeSubject.setValue(nodeSubject);
1109

    
1110
        } catch (NullPointerException e) {
1111
            String msg = "The 'targetNodeSubject' must be provided as a parameter and was not.";
1112
            logMetacat.error(msg);
1113
            throw new InvalidRequest("4873", msg);
1114

    
1115
        }
1116

    
1117
        result = CNodeService.getInstance(request).isNodeAuthorized(session, targetNodeSubject, identifier);
1118

    
1119
        response.setStatus(200);
1120
        response.setContentType("text/xml");
1121
        return result;
1122

    
1123
    }
1124

    
1125
    /**
1126
     * Pass the request to set the replication policy to CNodeService
1127
     * 
1128
     * @param pid
1129
     *            the identifier of the object to set the replication policy on
1130
     * 
1131
     * @throws NotImplemented
1132
     * @throws NotFound
1133
     * @throws NotAuthorized
1134
     * @throws ServiceFailure
1135
     * @throws InvalidRequest
1136
     * @throws InvalidToken
1137
     * @throws IOException
1138
     * @throws InstantiationException
1139
     * @throws IllegalAccessException
1140
     * @throws JiBXException
1141
     * @throws VersionMismatch 
1142
     */
1143
    public boolean setReplicationPolicy(String pid) throws NotImplemented,
1144
            NotFound, NotAuthorized, ServiceFailure, InvalidRequest,
1145
            InvalidToken, IOException, InstantiationException,
1146
            IllegalAccessException, JiBXException, VersionMismatch {
1147

    
1148
        boolean result = false;
1149
        ReplicationPolicy policy = null;
1150
        long serialVersion = 0L;
1151
        String serialVersionStr = null;
1152

    
1153
        Identifier identifier = new Identifier();
1154
        identifier.setValue(pid);
1155

    
1156
        policy = collectReplicationPolicy();
1157

    
1158
        // get the serialVersion
1159
        try {
1160
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1161
            serialVersion = new Long(serialVersionStr).longValue();
1162

    
1163
        } catch (NullPointerException e) {
1164
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1165
            logMetacat.error(msg);
1166
            throw new InvalidRequest("4883", msg);
1167

    
1168
        }
1169
        result = CNodeService.getInstance(request).setReplicationPolicy(
1170
                session, identifier, policy, serialVersion);
1171
        response.setStatus(200);
1172
        response.setContentType("text/xml");
1173
        return result;
1174

    
1175
    }
1176

    
1177
    /**
1178
     * Pass the request to set the replication status to CNodeService
1179
     * 
1180
     * @param pid
1181
     *            the identifier of the object to set the replication status on
1182
     * 
1183
     * @throws ServiceFailure
1184
     * @throws NotImplemented
1185
     * @throws InvalidToken
1186
     * @throws NotAuthorized
1187
     * @throws InvalidRequest
1188
     * @throws NotFound
1189
     * @throws JiBXException 
1190
     * @throws IllegalAccessException 
1191
     * @throws InstantiationException 
1192
     * @throws IOException 
1193
     */
1194
    public boolean setReplicationStatus(String pid) throws ServiceFailure,
1195
            NotImplemented, InvalidToken, NotAuthorized, InvalidRequest,
1196
            NotFound {
1197
        
1198
        boolean result = false;
1199
        Identifier identifier = new Identifier();
1200
        identifier.setValue(pid);
1201
        BaseException failure = null;
1202
        ReplicationStatus status = null;
1203
        String replicationStatus = null;
1204
        NodeReference targetNodeRef = null;
1205
        String targetNode = null;
1206

    
1207
        // Parse the params out of the multipart form data
1208
        // Read the incoming data from its Mime Multipart encoding
1209
        logMetacat.debug("Parsing ReplicaStatus from the mime multipart entity");
1210

    
1211
        try {
1212
            failure = collectReplicationStatus();
1213
            
1214
        } catch (IOException e2) {
1215
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1216
                e2.getMessage());
1217
            
1218
        } catch (InstantiationException e2) {
1219
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1220
                e2.getMessage());
1221
            
1222
        } catch (IllegalAccessException e2) {
1223
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1224
                    e2.getMessage());
1225
            
1226
        } catch (JiBXException e2) {
1227
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1228
                    e2.getMessage());
1229
            
1230
        }
1231
        
1232
        // get the replication status param
1233
        try {
1234
            replicationStatus = multipartparams.get("status").get(0);
1235
            status = ReplicationStatus.convert(replicationStatus);
1236

    
1237
        } catch (NullPointerException npe) {
1238

    
1239
            logMetacat.debug("The 'status' parameter was not found in the "
1240
                    + "multipartparams map.  Trying the params map.");
1241

    
1242
            try {
1243
                replicationStatus = params.get("status")[0];
1244
                status = ReplicationStatus.convert(replicationStatus
1245
                        .toLowerCase());
1246

    
1247
            } catch (Exception e) {
1248
                String msg = "The 'status' must be provided as a parameter and was not.";
1249
                logMetacat.error(msg);
1250
                throw new InvalidRequest("4730", msg);
1251

    
1252
            }
1253

    
1254
        }
1255

    
1256
        // get the target node reference param
1257
        try {
1258
            targetNode = multipartparams.get("nodeRef").get(0);
1259
            targetNodeRef = new NodeReference();
1260
            targetNodeRef.setValue(targetNode);
1261

    
1262
        } catch (NullPointerException e) {
1263
            logMetacat.debug("The 'nodeRef' parameter was not found in the "
1264
                    + "multipartparams map.  Trying the params map.");
1265

    
1266
            try {
1267
                targetNode = params.get("nodeRef")[0];
1268
                targetNodeRef = new NodeReference();
1269
                targetNodeRef.setValue(targetNode);
1270

    
1271
            } catch (Exception e1) {
1272
                String msg = "The 'nodeRef' must be provided as a parameter and was not.";
1273
                logMetacat.error(msg);
1274
                throw new InvalidRequest("4730", msg);
1275

    
1276
            }
1277

    
1278
        }
1279

    
1280
        result = CNodeService.getInstance(request).setReplicationStatus(
1281
                session, identifier, targetNodeRef, status, failure);
1282
        response.setStatus(200);
1283
        response.setContentType("text/xml");
1284
        return result;
1285

    
1286
    }
1287

    
1288
    /**
1289
     * Pass the request to update the replication metadata to CNodeService
1290
     * 
1291
     * @param pid
1292
     *            the identifier of the object to update the replication
1293
     *            metadata on
1294
     * 
1295
     * @throws ServiceFailure
1296
     * @throws NotImplemented
1297
     * @throws InvalidToken
1298
     * @throws NotAuthorized
1299
     * @throws InvalidRequest
1300
     * @throws NotFound
1301
     * @throws VersionMismatch 
1302
     */
1303
    public boolean updateReplicationMetadata(String pid) throws ServiceFailure,
1304
            NotImplemented, InvalidToken, NotAuthorized, InvalidRequest,
1305
            NotFound, VersionMismatch {
1306

    
1307
        boolean result = false;
1308
        long serialVersion = 0L;
1309
        String serialVersionStr = null;
1310
        Replica replica = null;
1311
        Identifier identifier = new Identifier();
1312
        identifier.setValue(pid);
1313

    
1314
        replica = collectReplicaMetadata();
1315

    
1316
        // get the serialVersion
1317
        try {
1318
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1319
            serialVersion = new Long(serialVersionStr).longValue();
1320

    
1321
        } catch (NullPointerException e) {
1322
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1323
            logMetacat.error(msg);
1324
            throw new InvalidRequest("4853", msg);
1325

    
1326
        }
1327

    
1328
        result = CNodeService.getInstance(request).updateReplicationMetadata(
1329
                session, identifier, replica, serialVersion);
1330
        response.setStatus(200);
1331
        response.setContentType("text/xml");
1332
        return result;
1333

    
1334
    }
1335

    
1336
}
(1-1/9)