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: 2011-12-16 16:24:17 -0800 (Fri, 16 Dec 2011) $'
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.types.v1.AccessPolicy;
58
import org.dataone.service.types.v1.Checksum;
59
import org.dataone.service.types.v1.ChecksumAlgorithmList;
60
import org.dataone.service.types.v1.DescribeResponse;
61
import org.dataone.service.types.v1.Event;
62
import org.dataone.service.types.v1.Identifier;
63
import org.dataone.service.types.v1.Log;
64
import org.dataone.service.types.v1.NodeReference;
65
import org.dataone.service.types.v1.ObjectFormat;
66
import org.dataone.service.types.v1.ObjectFormatIdentifier;
67
import org.dataone.service.types.v1.ObjectFormatList;
68
import org.dataone.service.types.v1.ObjectList;
69
import org.dataone.service.types.v1.ObjectLocationList;
70
import org.dataone.service.types.v1.Permission;
71
import org.dataone.service.types.v1.Replica;
72
import org.dataone.service.types.v1.ReplicationPolicy;
73
import org.dataone.service.types.v1.ReplicationStatus;
74
import org.dataone.service.types.v1.Subject;
75
import org.dataone.service.types.v1.SystemMetadata;
76
import org.dataone.service.util.Constants;
77
import org.dataone.service.util.DateTimeMarshaller;
78
import org.dataone.service.util.TypeMarshaller;
79
import org.jibx.runtime.JiBXException;
80
import org.xml.sax.SAXException;
81

    
82
import edu.ucsb.nceas.metacat.dataone.CNodeService;
83
import edu.ucsb.nceas.metacat.dataone.MNodeService;
84
import edu.ucsb.nceas.metacat.properties.PropertyService;
85
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
86

    
87
/**
88
 * CN REST service implementation handler
89
 * 
90
 * ****************** CNCore -- DONE create() - POST /d1/cn/object/PID
91
 * listFormats() - GET /d1/cn/formats getFormat() - GET /d1/cn/formats/FMTID
92
 * getLogRecords - GET /d1/cn/log reserveIdentifier() - POST /d1/cn/reserve
93
 * listNodes() - Not implemented registerSystemMetadata() - POST /d1/meta/PID
94
 * 
95
 * CNRead -- DONE get() - GET /d1/cn/object/PID getSystemMetadata() - GET
96
 * /d1/cn/meta/PID resolve() - GET /d1/cn/resolve/PID assertRelation() - GET
97
 * /d1/cn/assertRelation/PID getChecksum() - GET /d1/cn/checksum search() - Not
98
 * implemented in Metacat
99
 * 
100
 * CNAuthorization setOwner() - PUT /d1/cn/owner/PID isAuthorized() - GET
101
 * /d1/cn/isAuthorized/PID setAccessPolicy() - POST /d1/cn/accessRules
102
 * 
103
 * CNIdentity - not implemented at all on Metacat
104
 * 
105
 * CNReplication setReplicationStatus() - PUT /replicaNotifications/PID
106
 * updateReplicationMetadata() - PUT /replicaMetadata/PID setReplicationPolicy()
107
 * - PUT /replicaPolicies/PID isNodeAuthorized() - GET
108
 * /replicaAuthorizations/PID
109
 * 
110
 * CNRegister -- not implemented at all in Metacat ******************
111
 * 
112
 * @author leinfelder
113
 * 
114
 */
115
public class CNResourceHandler extends D1ResourceHandler {
116

    
117
    /** CN-specific operations **/
118
    protected static final String RESOURCE_RESERVE = "reserve";
119
    protected static final String RESOURCE_FORMATS = "formats";
120
    protected static final String RESOURCE_RESOLVE = "resolve";
121
    protected static final String RESOURCE_ASSERT_RELATION = "assertRelation";
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_ASSERT_RELATION)) {
194

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

    
198
                    // reserve the ID (in params)
199
                    if (httpVerb == GET) {
200
                        assertRelation(extra);
201
                        status = true;
202
                    }
203
                } else if (resource.startsWith(RESOURCE_RESOLVE)) {
204

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

    
208
                    // resolve the object location
209
                    if (httpVerb == GET) {
210
                        resolve(extra);
211
                        status = true;
212
                    }
213
                } else if (resource.startsWith(RESOURCE_OWNER)) {
214

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

    
218
                    // set the owner
219
                    if (httpVerb == PUT) {
220
                        owner(extra);
221
                        status = true;
222
                    }
223
                } else if (resource.startsWith(RESOURCE_IS_AUTHORIZED)) {
224

    
225
                    // after the command
226
                    extra = parseTrailing(resource, RESOURCE_IS_AUTHORIZED);
227

    
228
                    // authorized?
229
                    if (httpVerb == GET) {
230
                        isAuthorized(extra);
231
                        status = true;
232
                    }
233
                } else if (resource.startsWith(RESOURCE_OBJECTS)) {
234
                    logMetacat.debug("Using resource 'object'");
235
                    logMetacat
236
                            .debug("D1 Rest: Starting resource processing...");
237

    
238
                    // after the command
239
                    extra = parseTrailing(resource, RESOURCE_OBJECTS);
240

    
241
                    logMetacat.debug("objectId: " + extra);
242
                    logMetacat.debug("verb:" + httpVerb);
243

    
244
                    if (httpVerb == GET) {
245
                        if (extra != null) {
246
                            getObject(extra);
247
                        } else {
248
                            listObjects();
249
                        }
250
                        status = true;
251
                    } else if (httpVerb == POST) {
252
                        putObject(extra, FUNCTION_NAME_INSERT);
253
                        status = true;
254
                    } else if (httpVerb == HEAD) {
255
                        describeObject(extra);
256
                        status = true;
257
                    }
258

    
259
                } else if (resource.startsWith(RESOURCE_FORMATS)) {
260
                    logMetacat.debug("Using resource: " + RESOURCE_FORMATS);
261

    
262
                    // after the command
263
                    extra = parseTrailing(resource, RESOURCE_FORMATS);
264

    
265
                    // handle each verb
266
                    if (httpVerb == GET) {
267
                        if (extra == null) {
268
                            // list the formats collection
269
                            listFormats();
270
                        } else {
271
                            // get the specified format
272
                            getFormat(extra);
273
                        }
274
                        status = true;
275
                    }
276

    
277
                } else if (resource.startsWith(RESOURCE_LOG)) {
278
                    logMetacat.debug("Using resource: " + RESOURCE_LOG);
279
                    // handle log events
280
                    if (httpVerb == GET) {
281
                        getLog();
282
                        status = true;
283
                    }
284

    
285
                } else if (resource.startsWith(RESOURCE_CHECKSUM)) {
286
                    logMetacat.debug("Using resource: " + RESOURCE_CHECKSUM);
287

    
288
                    // after the command
289
                    extra = parseTrailing(resource, RESOURCE_CHECKSUM);
290

    
291
                    // handle checksum requests
292
                    if (httpVerb == GET) {
293

    
294
                        checksum(extra);
295
                        status = true;
296

    
297
                    }
298

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

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

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

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

    
319
                } else if (resource.startsWith(RESOURCE_REPLICATION_NOTIFY)
320
                        && httpVerb == PUT) {
321

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

    
329
                } else if (resource.startsWith(RESOURCE_REPLICATION_AUTHORIZED)
330
                        && httpVerb == GET) {
331

    
332
                    logMetacat.debug("Using resource: "
333
                            + RESOURCE_REPLICATION_AUTHORIZED);
334
                    // get the trailing pid
335
                    extra = parseTrailing(resource,
336
                            RESOURCE_REPLICATION_AUTHORIZED);
337
                    isNodeAuthorized(extra);
338
                    status = true;
339

    
340
                } else if (resource.startsWith(Constants.RESOURCE_MONITOR_PING)) {
341
                    if (httpVerb == GET) {
342
                    	// after the command
343
                        extra = parseTrailing(resource, Constants.RESOURCE_MONITOR_PING);
344
                        
345
                        logMetacat.debug("processing ping request");
346
                        Date result = CNodeService.getInstance(request).ping();
347
                        // TODO: send to output	
348
                        status = true;
349
                    }
350
                } else if (resource.startsWith(Constants.RESOURCE_CHECKSUM)) {
351
                    if (httpVerb == GET) {
352
                        listChecksumAlgorithms();
353
                        status = true;
354
                    }
355
                }
356

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

    
390
    /**
391
     * Get the checksum for the given guid
392
     * 
393
     * @param guid
394
     * @throws NotImplemented
395
     * @throws InvalidRequest
396
     * @throws NotFound
397
     * @throws NotAuthorized
398
     * @throws ServiceFailure
399
     * @throws InvalidToken
400
     * @throws IOException
401
     * @throws JiBXException
402
     */
403
    private void checksum(String guid) throws InvalidToken, ServiceFailure,
404
            NotAuthorized, NotFound, InvalidRequest, NotImplemented,
405
            JiBXException, IOException {
406
        Identifier guidid = new Identifier();
407
        guidid.setValue(guid);
408
        logMetacat.debug("getting checksum for object " + guid);
409
        Checksum c = CNodeService.getInstance(request).getChecksum(session,
410
                guidid);
411
        logMetacat.debug("got checksum " + c.getValue());
412
        response.setStatus(200);
413
        logMetacat.debug("serializing response");
414
        TypeMarshaller.marshalTypeToOutputStream(c, response.getOutputStream());
415
        logMetacat.debug("done serializing response.");
416

    
417
    }
418

    
419
    /**
420
     * get the logs based on passed params. Available params are token,
421
     * fromDate, toDate, event. See
422
     * http://mule1.dataone.org/ArchitectureDocs/mn_api_crud
423
     * .html#MN_crud.getLogRecords for more info
424
     * 
425
     * @throws NotImplemented
426
     * @throws InvalidRequest
427
     * @throws NotAuthorized
428
     * @throws ServiceFailure
429
     * @throws InvalidToken
430
     * @throws IOException
431
     * @throws JiBXException
432
     */
433
    private void getLog() throws InvalidToken, ServiceFailure, NotAuthorized,
434
            InvalidRequest, NotImplemented, IOException, JiBXException {
435

    
436
        Date fromDate = null;
437
        Date toDate = null;
438
        Event event = null;
439
        Integer start = null;
440
        Integer count = null;
441

    
442
        try {
443
            String fromDateS = params.get("fromDate")[0];
444
            logMetacat.debug("param fromDateS: " + fromDateS);
445
            fromDate = DateTimeMarshaller.deserializeDateToUTC(fromDateS);
446
        } catch (Exception e) {
447
            logMetacat.warn("Could not parse fromDate: " + e.getMessage());
448
        }
449
        try {
450
            String toDateS = params.get("toDate")[0];
451
            logMetacat.debug("param toDateS: " + toDateS);
452
            toDate = DateTimeMarshaller.deserializeDateToUTC(toDateS);
453
        } catch (Exception e) {
454
            logMetacat.warn("Could not parse toDate: " + e.getMessage());
455
        }
456
        try {
457
            String eventS = params.get("event")[0];
458
            event = Event.convert(eventS);
459
        } catch (Exception e) {
460
            logMetacat.warn("Could not parse event: " + e.getMessage());
461
        }
462
        logMetacat.debug("fromDate: " + fromDate + " toDate: " + toDate);
463

    
464
        try {
465
            start = Integer.parseInt(params.get("start")[0]);
466
        } catch (Exception e) {
467
            logMetacat.warn("Could not parse start: " + e.getMessage());
468
        }
469
        try {
470
            count = Integer.parseInt(params.get("count")[0]);
471
        } catch (Exception e) {
472
            logMetacat.warn("Could not parse count: " + e.getMessage());
473
        }
474

    
475
        logMetacat.debug("calling getLogRecords");
476
        Log log = CNodeService.getInstance(request).getLogRecords(session,
477
                fromDate, toDate, event, start, count);
478

    
479
        OutputStream out = response.getOutputStream();
480
        response.setStatus(200);
481
        response.setContentType("text/xml");
482

    
483
        TypeMarshaller.marshalTypeToOutputStream(log, out);
484

    
485
    }
486

    
487
    /**
488
     * Implements REST version of DataONE CRUD API --> get
489
     * 
490
     * @param guid
491
     *            ID of data object to be read
492
     * @throws NotImplemented
493
     * @throws InvalidRequest
494
     * @throws NotFound
495
     * @throws NotAuthorized
496
     * @throws ServiceFailure
497
     * @throws InvalidToken
498
     * @throws IOException
499
     */
500
    protected void getObject(String guid) throws InvalidToken, ServiceFailure,
501
            NotAuthorized, NotFound, InvalidRequest, NotImplemented,
502
            IOException {
503

    
504
        Identifier id = new Identifier();
505
        id.setValue(guid);
506

    
507
        SystemMetadata sm = CNodeService.getInstance(request)
508
                .getSystemMetadata(session, id);
509

    
510
        // set the content type
511
        if (sm.getFormatId()
512
                .getValue()
513
                .trim()
514
                .equals(ObjectFormatCache.getInstance().getFormat("text/csv")
515
                        .getFormatId().getValue())) {
516
            response.setContentType("text/csv");
517
            response.setHeader("Content-Disposition",
518
                    "inline; filename=" + id.getValue() + ".csv");
519
        } else if (sm
520
                .getFormatId()
521
                .getValue()
522
                .trim()
523
                .equals(ObjectFormatCache.getInstance().getFormat("text/plain")
524
                        .getFormatId().getValue())) {
525
            response.setContentType("text/plain");
526
            response.setHeader("Content-Disposition",
527
                    "inline; filename=" + id.getValue() + ".txt");
528
        } else if (sm
529
                .getFormatId()
530
                .getValue()
531
                .trim()
532
                .equals(ObjectFormatCache.getInstance()
533
                        .getFormat("application/octet-stream").getFormatId()
534
                        .getValue())) {
535
            response.setContentType("application/octet-stream");
536
        } else {
537
            response.setContentType("text/xml");
538
            response.setHeader("Content-Disposition",
539
                    "inline; filename=" + id.getValue() + ".xml");
540
        }
541

    
542
        InputStream data = CNodeService.getInstance(request).get(session, id);
543

    
544
        OutputStream out = response.getOutputStream();
545
        response.setStatus(200);
546
        IOUtils.copyLarge(data, out);
547

    
548
    }
549

    
550
    /**
551
     * Implements REST version of DataONE CRUD API --> getSystemMetadata
552
     * 
553
     * @param guid
554
     *            ID of data object to be read
555
     * @throws NotImplemented
556
     * @throws InvalidRequest
557
     * @throws NotFound
558
     * @throws NotAuthorized
559
     * @throws ServiceFailure
560
     * @throws InvalidToken
561
     * @throws IOException
562
     * @throws JiBXException
563
     */
564
    protected void getSystemMetadataObject(String guid) throws InvalidToken,
565
            ServiceFailure, NotAuthorized, NotFound, InvalidRequest,
566
            NotImplemented, IOException, JiBXException {
567

    
568
        Identifier id = new Identifier();
569
        id.setValue(guid);
570
        SystemMetadata sysmeta = CNodeService.getInstance(request)
571
                .getSystemMetadata(session, id);
572

    
573
        response.setContentType("text/xml");
574
        response.setStatus(200);
575
        OutputStream out = response.getOutputStream();
576

    
577
        // Serialize and write it to the output stream
578
        TypeMarshaller.marshalTypeToOutputStream(sysmeta, out);
579
    }
580

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

    
610
        // Read the incoming data from its Mime Multipart encoding
611
        Map<String, File> files = collectMultipartFiles();
612
        InputStream object = null;
613
        InputStream sysmeta = null;
614

    
615
        File smFile = files.get("sysmeta");
616
        sysmeta = new FileInputStream(smFile);
617
        File objFile = files.get("object");
618
        object = new FileInputStream(objFile);
619

    
620
        if (action.equals(FUNCTION_NAME_INSERT)) { // handle inserts
621

    
622
            logMetacat.debug("Commence creation...");
623
            SystemMetadata smd = TypeMarshaller.unmarshalTypeFromStream(
624
                    SystemMetadata.class, sysmeta);
625

    
626
            Identifier id = new Identifier();
627
            id.setValue(pid);
628
            logMetacat.debug("creating object with pid " + id.getValue());
629
            Identifier rId = CNodeService.getInstance(request).create(session,
630
                    id, object, smd);
631

    
632
            OutputStream out = response.getOutputStream();
633
            response.setStatus(200);
634
            response.setContentType("text/xml");
635

    
636
            TypeMarshaller.marshalTypeToOutputStream(rId, out);
637

    
638
        } else {
639
            throw new InvalidRequest("1000", "Operation must be create.");
640
        }
641
    }
642

    
643
    /**
644
     * List the object formats registered with the system
645
     * 
646
     * @throws NotImplemented
647
     * @throws InsufficientResources
648
     * @throws NotFound
649
     * @throws ServiceFailure
650
     * @throws InvalidRequest
651
     * @throws IOException
652
     * @throws JiBXException
653
     */
654
    private void listFormats() throws InvalidRequest, ServiceFailure, NotFound,
655
            InsufficientResources, NotImplemented, IOException, JiBXException {
656
        logMetacat.debug("Entering listFormats()");
657

    
658
        ObjectFormatList objectFormatList = CNodeService.getInstance(request)
659
                .listFormats();
660
        // get the response output stream
661
        OutputStream out = response.getOutputStream();
662
        response.setStatus(200);
663
        response.setContentType("text/xml");
664

    
665
        // style the object with a processing directive
666
        String stylesheet = null;
667
        try {
668
            stylesheet = PropertyService.getProperty("dataone.types.xsl");
669
        } catch (PropertyNotFoundException e) {
670
            logMetacat.warn("Could not locate DataONE types XSLT: "
671
                    + e.getMessage());
672
        }
673

    
674
        TypeMarshaller.marshalTypeToOutputStream(objectFormatList, out,
675
                stylesheet);
676

    
677
    }
678
    
679
    private void listChecksumAlgorithms() throws IOException, ServiceFailure,
680
			NotImplemented, JiBXException {
681
		logMetacat.debug("Entering listFormats()");
682

    
683
		ChecksumAlgorithmList result = CNodeService.getInstance(request).listChecksumAlgorithms();
684

    
685
		// get the response output stream
686
		OutputStream out = response.getOutputStream();
687
		response.setStatus(200);
688
		response.setContentType("text/xml");
689

    
690
		// style the object with a processing directive
691
		String stylesheet = null;
692
		try {
693
			stylesheet = PropertyService.getProperty("dataone.types.xsl");
694
		} catch (PropertyNotFoundException e) {
695
			logMetacat.warn("Could not locate DataONE types XSLT: "
696
					+ e.getMessage());
697
		}
698

    
699
		TypeMarshaller.marshalTypeToOutputStream(result, out, stylesheet);
700

    
701
	}
702
    
703
    /**
704
     * http://mule1.dataone.org/ArchitectureDocs-current/apis/CN_APIs.html#CNRead.describe
705
     * @param pid
706
     * @throws InvalidToken
707
     * @throws ServiceFailure
708
     * @throws NotAuthorized
709
     * @throws NotFound
710
     * @throws NotImplemented
711
     * @throws InvalidRequest
712
     */
713
    private void describeObject(String pid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, InvalidRequest
714
    {
715
        response.setStatus(200);
716
        response.setContentType("text/xml");
717
        
718
        Identifier id = new Identifier();
719
        id.setValue(pid);
720

    
721
        DescribeResponse dr = CNodeService.getInstance(request).describe(session, id);
722
        //response.addHeader("pid", pid);
723
        response.addHeader("DataONE-Checksum", dr.getDataONE_Checksum().getAlgorithm() + "," + dr.getDataONE_Checksum().getValue());
724
        response.addHeader("Content-Length", dr.getContent_Length() + "");
725
        response.addHeader("Last-Modified", DateTimeMarshaller.serializeDateToUTC(dr.getLast_Modified()));
726
        response.addHeader("DataONE-ObjectFormat", dr.getDataONE_ObjectFormatIdentifier().getValue());
727
        response.addHeader("DataONE-SerialVersion", dr.getSerialVersion().toString());
728

    
729
    }
730

    
731
    /**
732
     * Return the requested object format
733
     * 
734
     * @param fmtidStr
735
     *            the requested format identifier as a string
736
     * @throws NotImplemented
737
     * @throws InsufficientResources
738
     * @throws NotFound
739
     * @throws ServiceFailure
740
     * @throws InvalidRequest
741
     * @throws IOException
742
     * @throws JiBXException
743
     */
744
    private void getFormat(String fmtidStr) throws InvalidRequest,
745
            ServiceFailure, NotFound, InsufficientResources, NotImplemented,
746
            IOException, JiBXException {
747
        logMetacat.debug("Entering listFormats()");
748

    
749
        ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
750
        fmtid.setValue(fmtidStr);
751

    
752
        // get the specified object format
753
        ObjectFormat objectFormat = CNodeService.getInstance(request)
754
                .getFormat(fmtid);
755

    
756
        OutputStream out = response.getOutputStream();
757
        response.setStatus(200);
758
        response.setContentType("text/xml");
759

    
760
        TypeMarshaller.marshalTypeToOutputStream(objectFormat, out);
761

    
762
    }
763

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

    
810
    /**
811
     * 
812
     * @param id
813
     * @throws InvalidRequest
814
     * @throws InvalidToken
815
     * @throws ServiceFailure
816
     * @throws NotAuthorized
817
     * @throws NotFound
818
     * @throws NotImplemented
819
     * @throws IOException
820
     * @throws JiBXException
821
     */
822
    private void resolve(String id) throws InvalidRequest, InvalidToken,
823
            ServiceFailure, NotAuthorized, NotFound, NotImplemented,
824
            IOException, JiBXException {
825
        Identifier pid = new Identifier();
826
        pid.setValue(id);
827
        ObjectLocationList locationList = CNodeService.getInstance(request)
828
                .resolve(session, pid);
829
        OutputStream out = response.getOutputStream();
830
        response.setStatus(200);
831
        response.setContentType("text/xml");
832
        TypeMarshaller.marshalTypeToOutputStream(locationList, out);
833

    
834
    }
835

    
836
    /**
837
     * Assert that a relationship exists between two resources
838
     * 
839
     * @param id
840
     * @return
841
     * @throws InvalidToken
842
     * @throws ServiceFailure
843
     * @throws NotAuthorized
844
     * @throws NotFound
845
     * @throws InvalidRequest
846
     * @throws NotImplemented
847
     */
848
    private boolean assertRelation(String id) throws InvalidToken,
849
            ServiceFailure, NotAuthorized, NotFound, InvalidRequest,
850
            NotImplemented {
851
        Identifier pidOfSubject = new Identifier();
852
        pidOfSubject.setValue(id);
853
        String relationship = null;
854
        try {
855
            relationship = params.get("relationship")[0];
856
        } catch (Exception e) {
857
            logMetacat.warn("relationship not specified");
858
        }
859
        Identifier pidOfObject = new Identifier();
860
        try {
861
            String objPid = params.get("pidOfObject")[0];
862
            pidOfObject.setValue(objPid);
863
        } catch (Exception e) {
864
            logMetacat.warn("pidOfObject not specified");
865
        }
866
        boolean result = CNodeService.getInstance(request).assertRelation(
867
                session, pidOfSubject, relationship, pidOfObject);
868
        response.setStatus(200);
869
        response.setContentType("text/xml");
870
        return result;
871
    }
872

    
873
    /**
874
     * Set the owner of a resource
875
     * 
876
     * @param id
877
     * @throws JiBXException
878
     * @throws InvalidToken
879
     * @throws ServiceFailure
880
     * @throws NotFound
881
     * @throws NotAuthorized
882
     * @throws NotImplemented
883
     * @throws InvalidRequest
884
     * @throws IOException
885
     * @throws IllegalAccessException
886
     * @throws InstantiationException
887
     */
888
    private void owner(String id) throws JiBXException, InvalidToken,
889
            ServiceFailure, NotFound, NotAuthorized, NotImplemented,
890
            InvalidRequest, IOException, InstantiationException,
891
            IllegalAccessException {
892

    
893
        Identifier pid = new Identifier();
894
        pid.setValue(id);
895

    
896
        long serialVersion = 0L;
897
        String serialVersionStr = null;
898

    
899
        // get the serialVersion
900
        try {
901
            serialVersionStr = params.get("serialVersion")[0];
902
            serialVersion = new Long(serialVersionStr).longValue();
903

    
904
        } catch (NullPointerException e) {
905
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
906
            logMetacat.error(msg);
907
            throw new InvalidRequest("4442", msg);
908

    
909
        }
910

    
911
        // get the subject
912
        String subjectStr = params.get("subject")[0];
913
        Subject subject = TypeMarshaller.unmarshalTypeFromStream(Subject.class,
914
                new ByteArrayInputStream(subjectStr.getBytes("UTF-8")));
915

    
916
        Identifier retPid = CNodeService.getInstance(request).setRightsHolder(session, pid, subject, serialVersion);
917
        OutputStream out = response.getOutputStream();
918
        response.setStatus(200);
919
        response.setContentType("text/xml");
920
        TypeMarshaller.marshalTypeToOutputStream(retPid, out);
921
    }
922

    
923
    /**
924
     * Processes the authorization check for given id
925
     * 
926
     * @param id
927
     * @return
928
     * @throws ServiceFailure
929
     * @throws InvalidToken
930
     * @throws NotFound
931
     * @throws NotAuthorized
932
     * @throws NotImplemented
933
     * @throws InvalidRequest
934
     */
935
    private boolean isAuthorized(String id) throws ServiceFailure,
936
            InvalidToken, NotFound, NotAuthorized, NotImplemented,
937
            InvalidRequest {
938
        Identifier pid = new Identifier();
939
        pid.setValue(id);
940
        String permission = params.get("action")[0];
941
        boolean result = CNodeService.getInstance(request).isAuthorized(
942
                session, pid, Permission.convert(permission));
943
        response.setStatus(200);
944
        response.setContentType("text/xml");
945
        return result;
946
    }
947

    
948
    /**
949
     * Register System Metadata without data or metadata object
950
     * 
951
     * @param pid
952
     *            identifier for System Metadata entry
953
     * @throws JiBXException
954
     * @throws FileUploadException
955
     * @throws IOException
956
     * @throws InvalidRequest
957
     * @throws ServiceFailure
958
     * @throws InvalidSystemMetadata
959
     * @throws NotAuthorized
960
     * @throws NotImplemented
961
     * @throws IllegalAccessException
962
     * @throws InstantiationException
963
     */
964
    protected Identifier registerSystemMetadata(String pid)
965
            throws ServiceFailure, InvalidRequest, IOException,
966
            FileUploadException, JiBXException, NotImplemented, NotAuthorized,
967
            InvalidSystemMetadata, InstantiationException,
968
            IllegalAccessException {
969
        logMetacat.debug("Entering registerSystemMetadata: " + pid);
970

    
971
        // get the system metadata from the request
972
        SystemMetadata systemMetadata = collectSystemMetadata();
973

    
974
        Identifier guid = new Identifier();
975
        guid.setValue(pid);
976
        logMetacat.debug("registering system metadata with pid "
977
                + guid.getValue());
978
        Identifier retGuid = CNodeService.getInstance(request)
979
                .registerSystemMetadata(session, guid, systemMetadata);
980

    
981
        response.setStatus(200);
982
        response.setContentType("text/xml");
983
        return retGuid;
984

    
985
    }
986

    
987
    /**
988
     * set the access perms on a document
989
     * 
990
     * @throws JiBXException
991
     * @throws InvalidRequest
992
     * @throws NotImplemented
993
     * @throws NotAuthorized
994
     * @throws NotFound
995
     * @throws ServiceFailure
996
     * @throws InvalidToken
997
     * @throws IllegalAccessException
998
     * @throws InstantiationException
999
     * @throws IOException
1000
     * @throws SAXException
1001
     * @throws ParserConfigurationException
1002
     */
1003
    protected void setAccess(String pid) throws JiBXException, InvalidToken,
1004
            ServiceFailure, NotFound, NotAuthorized, NotImplemented,
1005
            InvalidRequest, IOException, InstantiationException,
1006
            IllegalAccessException, ParserConfigurationException, SAXException {
1007

    
1008
        long serialVersion = 0L;
1009
        String serialVersionStr = null;
1010

    
1011
        // get the serialVersion
1012
        try {
1013
            serialVersionStr = params.get("serialVersion")[0];
1014
            serialVersion = new Long(serialVersionStr).longValue();
1015

    
1016
        } catch (NullPointerException e) {
1017
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1018
            logMetacat.error(msg);
1019
            throw new InvalidRequest("4402", msg);
1020

    
1021
        }
1022

    
1023
        Identifier id = new Identifier();
1024
        id.setValue(pid);
1025

    
1026
        AccessPolicy accessPolicy = collectAccessPolicy();
1027
        CNodeService.getInstance(request).setAccessPolicy(session, id,
1028
                accessPolicy, serialVersion);
1029

    
1030
    }
1031

    
1032
    /**
1033
     * List the objects
1034
     * 
1035
     * @throws NotImplemented
1036
     * @throws InvalidRequest
1037
     * @throws NotAuthorized
1038
     * @throws ServiceFailure
1039
     * @throws InvalidToken
1040
     * @throws NotFound
1041
     * @throws IOException
1042
     * @throws JiBXException
1043
     * @throws Exception
1044
     */
1045
    private void listObjects() throws InvalidToken, ServiceFailure,
1046
            NotAuthorized, InvalidRequest, NotImplemented, NotFound,
1047
            IOException, JiBXException {
1048

    
1049
        Date startTime = null;
1050
        Date endTime = null;
1051
        ObjectFormat objectFormat = null;
1052
        boolean replicaStatus = false;
1053
        int start = 0;
1054
        int count = -1;
1055
        Enumeration<String> paramlist = request.getParameterNames();
1056
        while (paramlist.hasMoreElements()) {
1057
            // parse the params and make the call
1058
            String name = paramlist.nextElement();
1059
            String[] value = request.getParameterValues(name);
1060

    
1061
            if (name.equals("startTime") && value != null) {
1062
                try {
1063
                    startTime = DateTimeMarshaller
1064
                            .deserializeDateToUTC(value[0]);
1065
                } catch (Exception e) {
1066
                    // if we can't parse it, just don't use the startTime param
1067
                    logMetacat.warn("Could not parse startTime: " + value[0]);
1068
                    startTime = null;
1069
                }
1070
            } else if (name.equals("endTime") && value != null) {
1071
                try {
1072
                    endTime = DateTimeMarshaller.deserializeDateToUTC(value[0]);
1073
                } catch (Exception e) {
1074
                    // if we can't parse it, just don't use the endTime param
1075
                    logMetacat.warn("Could not parse endTime: " + value[0]);
1076
                    endTime = null;
1077
                }
1078
            } else if (name.equals("objectFormat") && value != null) {
1079
                objectFormat = ObjectFormatCache.getInstance().getFormat(
1080
                        value[0]);
1081
            } else if (name.equals("replicaStatus") && value != null) {
1082
                replicaStatus = Boolean.parseBoolean(value[0]);
1083
            } else if (name.equals("start") && value != null) {
1084
                start = Integer.valueOf(value[0]);
1085
            } else if (name.equals("count") && value != null) {
1086
                count = Integer.valueOf(value[0]);
1087
            }
1088
        }
1089
        // make the call
1090
        logMetacat.debug("session: " + session + " startTime: " + startTime
1091
                + " endtime: " + endTime + " objectFormat: " + objectFormat
1092
                + " replicaStatus: " + replicaStatus + " start: " + start
1093
                + " count: " + count);
1094

    
1095
        ObjectFormatIdentifier fmtid = null;
1096
        if (objectFormat != null) {
1097
            fmtid = objectFormat.getFormatId();
1098
        }
1099

    
1100
        // get the list
1101
        ObjectList ol = CNodeService.getInstance(request).listObjects(session,
1102
                startTime, endTime, fmtid, replicaStatus, start, count);
1103

    
1104
        // send it
1105
        OutputStream out = response.getOutputStream();
1106
        response.setStatus(200);
1107
        response.setContentType("text/xml");
1108

    
1109
        // style the object with a processing directive
1110
        String stylesheet = null;
1111
        try {
1112
            stylesheet = PropertyService.getProperty("dataone.types.xsl");
1113
        } catch (PropertyNotFoundException e) {
1114
            logMetacat.warn("Could not locate DataONE types XSLT: "
1115
                    + e.getMessage());
1116
        }
1117

    
1118
        // Serialize and write it to the output stream
1119
        TypeMarshaller.marshalTypeToOutputStream(ol, out, stylesheet);
1120
    }
1121

    
1122
    /**
1123
     * Pass the request to get node replication authorization to CNodeService
1124
     * 
1125
     * @param pid
1126
     *            the identifier of the object to get authorization to replicate
1127
     * 
1128
     * @throws NotImplemented
1129
     * @throws NotAuthorized
1130
     * @throws InvalidToken
1131
     * @throws ServiceFailure
1132
     * @throws NotFound
1133
     * @throws InvalidRequest
1134
     */
1135
    public boolean isNodeAuthorized(String pid) throws NotImplemented,
1136
            NotAuthorized, InvalidToken, ServiceFailure, NotFound,
1137
            InvalidRequest {
1138

    
1139
        boolean result = false;
1140
        Subject targetNodeSubject = new Subject();
1141
        String nodeSubject = null;
1142
        String replPermission = null;
1143

    
1144
        // get the pid
1145
        Identifier identifier = new Identifier();
1146
        identifier.setValue(pid);
1147

    
1148
        // get the target node subject
1149
        try {
1150
            nodeSubject = params.get("targetNodeSubject")[0];
1151
            targetNodeSubject.setValue(nodeSubject);
1152

    
1153
        } catch (NullPointerException e) {
1154
            String msg = "The 'targetNodeSubject' must be provided as a parameter and was not.";
1155
            logMetacat.error(msg);
1156
            throw new InvalidRequest("4873", msg);
1157

    
1158
        }
1159

    
1160
        result = CNodeService.getInstance(request).isNodeAuthorized(session, targetNodeSubject, identifier);
1161

    
1162
        response.setStatus(200);
1163
        response.setContentType("text/xml");
1164
        return result;
1165

    
1166
    }
1167

    
1168
    /**
1169
     * Pass the request to set the replication policy to CNodeService
1170
     * 
1171
     * @param pid
1172
     *            the identifier of the object to set the replication policy on
1173
     * 
1174
     * @throws NotImplemented
1175
     * @throws NotFound
1176
     * @throws NotAuthorized
1177
     * @throws ServiceFailure
1178
     * @throws InvalidRequest
1179
     * @throws InvalidToken
1180
     * @throws IOException
1181
     * @throws InstantiationException
1182
     * @throws IllegalAccessException
1183
     * @throws JiBXException
1184
     */
1185
    public boolean setReplicationPolicy(String pid) throws NotImplemented,
1186
            NotFound, NotAuthorized, ServiceFailure, InvalidRequest,
1187
            InvalidToken, IOException, InstantiationException,
1188
            IllegalAccessException, JiBXException {
1189

    
1190
        boolean result = false;
1191
        ReplicationPolicy policy = null;
1192
        long serialVersion = 0L;
1193
        String serialVersionStr = null;
1194

    
1195
        Identifier identifier = new Identifier();
1196
        identifier.setValue(pid);
1197

    
1198
        policy = collectReplicationPolicy();
1199

    
1200
        // get the serialVersion
1201
        try {
1202
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1203
            serialVersion = new Long(serialVersionStr).longValue();
1204

    
1205
        } catch (NullPointerException e) {
1206
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1207
            logMetacat.error(msg);
1208
            throw new InvalidRequest("4883", msg);
1209

    
1210
        }
1211
        result = CNodeService.getInstance(request).setReplicationPolicy(
1212
                session, identifier, policy, serialVersion);
1213
        response.setStatus(200);
1214
        response.setContentType("text/xml");
1215
        return result;
1216

    
1217
    }
1218

    
1219
    /**
1220
     * Pass the request to set the replication status to CNodeService
1221
     * 
1222
     * @param pid
1223
     *            the identifier of the object to set the replication status on
1224
     * 
1225
     * @throws ServiceFailure
1226
     * @throws NotImplemented
1227
     * @throws InvalidToken
1228
     * @throws NotAuthorized
1229
     * @throws InvalidRequest
1230
     * @throws NotFound
1231
     * @throws JiBXException 
1232
     * @throws IllegalAccessException 
1233
     * @throws InstantiationException 
1234
     * @throws IOException 
1235
     */
1236
    public boolean setReplicationStatus(String pid) throws ServiceFailure,
1237
            NotImplemented, InvalidToken, NotAuthorized, InvalidRequest,
1238
            NotFound {
1239
        
1240
        boolean result = false;
1241
        Identifier identifier = new Identifier();
1242
        identifier.setValue(pid);
1243
        BaseException failure = null;
1244
        ReplicationStatus status = null;
1245
        String replicationStatus = null;
1246
        NodeReference targetNodeRef = null;
1247
        String targetNode = null;
1248

    
1249
        // Parse the params out of the multipart form data
1250
        // Read the incoming data from its Mime Multipart encoding
1251
        logMetacat.debug("Parsing ReplicaStatus from the mime multipart entity");
1252

    
1253
        try {
1254
            failure = collectReplicationStatus();
1255
            
1256
        } catch (IOException e2) {
1257
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1258
                e2.getMessage());
1259
            
1260
        } catch (InstantiationException e2) {
1261
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1262
                e2.getMessage());
1263
            
1264
        } catch (IllegalAccessException e2) {
1265
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1266
                    e2.getMessage());
1267
            
1268
        } catch (JiBXException e2) {
1269
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1270
                    e2.getMessage());
1271
            
1272
        }
1273
        
1274
        // get the replication status param
1275
        try {
1276
            replicationStatus = multipartparams.get("status").get(0);
1277
            status = ReplicationStatus.convert(replicationStatus);
1278

    
1279
        } catch (NullPointerException npe) {
1280

    
1281
            logMetacat.debug("The 'status' parameter was not found in the "
1282
                    + "multipartparams map.  Trying the params map.");
1283

    
1284
            try {
1285
                replicationStatus = params.get("status")[0];
1286
                status = ReplicationStatus.convert(replicationStatus
1287
                        .toLowerCase());
1288

    
1289
            } catch (Exception e) {
1290
                String msg = "The 'status' must be provided as a parameter and was not.";
1291
                logMetacat.error(msg);
1292
                throw new InvalidRequest("4730", msg);
1293

    
1294
            }
1295

    
1296
        }
1297

    
1298
        // get the target node reference param
1299
        try {
1300
            targetNode = multipartparams.get("nodeRef").get(0);
1301
            targetNodeRef = new NodeReference();
1302
            targetNodeRef.setValue(targetNode);
1303

    
1304
        } catch (NullPointerException e) {
1305
            logMetacat.debug("The 'nodeRef' parameter was not found in the "
1306
                    + "multipartparams map.  Trying the params map.");
1307

    
1308
            try {
1309
                targetNode = params.get("nodeRef")[0];
1310
                targetNodeRef = new NodeReference();
1311
                targetNodeRef.setValue(targetNode);
1312

    
1313
            } catch (Exception e1) {
1314
                String msg = "The 'nodeRef' must be provided as a parameter and was not.";
1315
                logMetacat.error(msg);
1316
                throw new InvalidRequest("4730", msg);
1317

    
1318
            }
1319

    
1320
        }
1321

    
1322
        result = CNodeService.getInstance(request).setReplicationStatus(
1323
                session, identifier, targetNodeRef, status, failure);
1324
        response.setStatus(200);
1325
        response.setContentType("text/xml");
1326
        return result;
1327

    
1328
    }
1329

    
1330
    /**
1331
     * Pass the request to update the replication metadata to CNodeService
1332
     * 
1333
     * @param pid
1334
     *            the identifier of the object to update the replication
1335
     *            metadata on
1336
     * 
1337
     * @throws ServiceFailure
1338
     * @throws NotImplemented
1339
     * @throws InvalidToken
1340
     * @throws NotAuthorized
1341
     * @throws InvalidRequest
1342
     * @throws NotFound
1343
     */
1344
    public boolean updateReplicationMetadata(String pid) throws ServiceFailure,
1345
            NotImplemented, InvalidToken, NotAuthorized, InvalidRequest,
1346
            NotFound {
1347

    
1348
        boolean result = false;
1349
        long serialVersion = 0L;
1350
        String serialVersionStr = null;
1351
        Replica replica = null;
1352
        Identifier identifier = new Identifier();
1353
        identifier.setValue(pid);
1354

    
1355
        replica = collectReplicaMetadata();
1356

    
1357
        // get the serialVersion
1358
        try {
1359
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1360
            serialVersion = new Long(serialVersionStr).longValue();
1361

    
1362
        } catch (NullPointerException e) {
1363
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1364
            logMetacat.error(msg);
1365
            throw new InvalidRequest("4853", msg);
1366

    
1367
        }
1368

    
1369
        result = CNodeService.getInstance(request).updateReplicationMetadata(
1370
                session, identifier, replica, serialVersion);
1371
        response.setStatus(200);
1372
        response.setContentType("text/xml");
1373
        return result;
1374

    
1375
    }
1376

    
1377
}
(1-1/9)