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-03-08 11:18:21 -0800 (Thu, 08 Mar 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.service.exceptions.BaseException;
45
import org.dataone.service.exceptions.IdentifierNotUnique;
46
import org.dataone.service.exceptions.InsufficientResources;
47
import org.dataone.service.exceptions.InvalidRequest;
48
import org.dataone.service.exceptions.InvalidSystemMetadata;
49
import org.dataone.service.exceptions.InvalidToken;
50
import org.dataone.service.exceptions.NotAuthorized;
51
import org.dataone.service.exceptions.NotFound;
52
import org.dataone.service.exceptions.NotImplemented;
53
import org.dataone.service.exceptions.ServiceFailure;
54
import org.dataone.service.exceptions.UnsupportedType;
55
import org.dataone.service.exceptions.VersionMismatch;
56
import org.dataone.service.types.v1.AccessPolicy;
57
import org.dataone.service.types.v1.Checksum;
58
import org.dataone.service.types.v1.ChecksumAlgorithmList;
59
import org.dataone.service.types.v1.DescribeResponse;
60
import org.dataone.service.types.v1.Event;
61
import org.dataone.service.types.v1.Identifier;
62
import org.dataone.service.types.v1.Log;
63
import org.dataone.service.types.v1.NodeReference;
64
import org.dataone.service.types.v1.ObjectFormat;
65
import org.dataone.service.types.v1.ObjectFormatIdentifier;
66
import org.dataone.service.types.v1.ObjectFormatList;
67
import org.dataone.service.types.v1.ObjectList;
68
import org.dataone.service.types.v1.ObjectLocationList;
69
import org.dataone.service.types.v1.Permission;
70
import org.dataone.service.types.v1.Replica;
71
import org.dataone.service.types.v1.ReplicationPolicy;
72
import org.dataone.service.types.v1.ReplicationStatus;
73
import org.dataone.service.types.v1.Subject;
74
import org.dataone.service.types.v1.SystemMetadata;
75
import org.dataone.service.util.Constants;
76
import org.dataone.service.util.DateTimeMarshaller;
77
import org.dataone.service.util.EncodingUtilities;
78
import org.dataone.service.util.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.properties.PropertyService;
84
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
85

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

    
116
    /** CN-specific operations **/
117
    protected static final String RESOURCE_RESERVE = "reserve";
118
    protected static final String RESOURCE_FORMATS = "formats";
119
    protected static final String RESOURCE_RESOLVE = "resolve";
120
    protected static final String RESOURCE_OWNER = "owner";
121
    protected static final String RESOURCE_REPLICATION_POLICY = "replicaPolicies";
122
    protected static final String RESOURCE_REPLICATION_META = "replicaMetadata";
123
    protected static final String RESOURCE_REPLICATION_AUTHORIZED = "replicaAuthorizations";
124
    protected static final String RESOURCE_REPLICATION_NOTIFY = "replicaNotifications";
125

    
126
    public CNResourceHandler(ServletContext servletContext,
127
            HttpServletRequest request, HttpServletResponse response) {
128
        super(servletContext, request, response);
129
        logMetacat = Logger.getLogger(CNResourceHandler.class);
130
    }
131

    
132
    /**
133
     * This function is called from REST API servlet and handles each request to
134
     * the servlet
135
     * 
136
     * @param httpVerb
137
     *            (GET, POST, PUT or DELETE)
138
     */
139
    @Override
140
    public void handle(byte httpVerb) {
141
        // prepare the handler
142
        super.handle(httpVerb);
143

    
144
        try {
145

    
146
        	// only service requests if we have D1 configured
147
        	if (!isD1Enabled()) {
148
        		ServiceFailure se = new ServiceFailure("0000", "DataONE services are not enabled on this node");
149
                serializeException(se, response.getOutputStream());
150
                return;
151
        	}
152
        	
153
            // get the resource
154
            String resource = request.getPathInfo();
155
            resource = resource.substring(resource.indexOf("/") + 1);
156

    
157
            // for the rest of the resouce
158
            String extra = null;
159

    
160
            logMetacat.debug("handling verb " + httpVerb
161
                    + " request with resource '" + resource + "'");
162
            boolean status = false;
163

    
164
            if (resource != null) {
165

    
166
                if (resource.startsWith(RESOURCE_ACCESS_RULES)
167
                        && httpVerb == PUT) {
168
                    logMetacat.debug("Setting access policy");
169
                    // after the command
170
                    extra = parseTrailing(resource, RESOURCE_ACCESS_RULES);
171
                    setAccess(extra);
172
                    status = true;
173
                    logMetacat.debug("done setting access");
174

    
175
                } else if (resource.startsWith(RESOURCE_META)) {
176
                    logMetacat.debug("Using resource: " + RESOURCE_META);
177

    
178
                    // after the command
179
                    extra = parseTrailing(resource, RESOURCE_META);
180

    
181
                    // get
182
                    if (httpVerb == GET) {
183
                        getSystemMetadataObject(extra);
184
                        status = true;
185
                    }
186
                    // post to register system metadata
187
                    if (httpVerb == POST) {
188
                        registerSystemMetadata();
189
                        status = true;
190
                    }
191

    
192
                } else if (resource.startsWith(RESOURCE_RESERVE)) {
193
                    // reserve the ID (in params)
194
                    if (httpVerb == POST) {
195
                        reserve();
196
                        status = true;
197
                    }
198
                } else if (resource.startsWith(RESOURCE_RESOLVE)) {
199

    
200
                    // after the command
201
                    extra = parseTrailing(resource, RESOURCE_RESOLVE);
202

    
203
                    // resolve the object location
204
                    if (httpVerb == GET) {
205
                        resolve(extra);
206
                        status = true;
207
                    }
208
                } else if (resource.startsWith(RESOURCE_OWNER)) {
209

    
210
                    // after the command
211
                    extra = parseTrailing(resource, RESOURCE_OWNER);
212

    
213
                    // set the owner
214
                    if (httpVerb == PUT) {
215
                        owner(extra);
216
                        status = true;
217
                    }
218
                } else if (resource.startsWith(RESOURCE_IS_AUTHORIZED)) {
219

    
220
                    // after the command
221
                    extra = parseTrailing(resource, RESOURCE_IS_AUTHORIZED);
222

    
223
                    // authorized?
224
                    if (httpVerb == GET) {
225
                        isAuthorized(extra);
226
                        status = true;
227
                    }
228
                } else if (resource.startsWith(RESOURCE_OBJECTS)) {
229
                    logMetacat.debug("Using resource 'object'");
230
                    logMetacat
231
                            .debug("D1 Rest: Starting resource processing...");
232

    
233
                    // after the command
234
                    extra = parseTrailing(resource, RESOURCE_OBJECTS);
235

    
236
                    logMetacat.debug("objectId: " + extra);
237
                    logMetacat.debug("verb:" + httpVerb);
238

    
239
                    if (httpVerb == GET) {
240
                        if (extra != null) {
241
                            getObject(extra);
242
                        } else {
243
                            listObjects();
244
                        }
245
                        status = true;
246
                    } else if (httpVerb == POST) {
247
                        putObject(FUNCTION_NAME_INSERT);
248
                        status = true;
249
                    } else if (httpVerb == HEAD) {
250
                        describeObject(extra);
251
                        status = true;
252
                    }
253

    
254
                } else if (resource.startsWith(RESOURCE_FORMATS)) {
255
                    logMetacat.debug("Using resource: " + RESOURCE_FORMATS);
256

    
257
                    // after the command
258
                    extra = parseTrailing(resource, RESOURCE_FORMATS);
259

    
260
                    // handle each verb
261
                    if (httpVerb == GET) {
262
                        if (extra == null) {
263
                            // list the formats collection
264
                            listFormats();
265
                        } else {
266
                            // get the specified format
267
                            getFormat(extra);
268
                        }
269
                        status = true;
270
                    }
271

    
272
                } else if (resource.startsWith(RESOURCE_LOG)) {
273
                    logMetacat.debug("Using resource: " + RESOURCE_LOG);
274
                    // handle log events
275
                    if (httpVerb == GET) {
276
                        getLog();
277
                        status = true;
278
                    }
279

    
280
                } else if (resource.startsWith(Constants.RESOURCE_CHECKSUM)) {
281
                    logMetacat.debug("Using resource: " + Constants.RESOURCE_CHECKSUM);
282

    
283
                    // after the command
284
                    extra = parseTrailing(resource, Constants.RESOURCE_CHECKSUM);
285

    
286
                    // handle checksum requests
287
                    if (httpVerb == GET) {
288

    
289
                    	if (extra != null && extra.length() > 0) {
290
	                        checksum(extra);
291
	                        status = true;
292
                    	} else {
293
                    		listChecksumAlgorithms();
294
                    		status = true;
295
                    	}
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_META_OBSOLETEDBY)
351
                        && httpVerb == PUT) {
352

    
353
                    logMetacat.debug("Using resource: "
354
                            + Constants.RESOURCE_META_OBSOLETEDBY);
355
                    // get the trailing pid
356
                    extra = parseTrailing(resource, Constants.RESOURCE_META_OBSOLETEDBY);
357
                    setObsoletedBy(extra);
358
                    status = true;
359
                } else if (resource.startsWith(Constants.RESOURCE_REPLICATION_DELETE_REPLICA)
360
                        && httpVerb == PUT) {
361

    
362
                    logMetacat.debug("Using resource: "
363
                            + Constants.RESOURCE_REPLICATION_DELETE_REPLICA);
364
                    // get the trailing pid
365
                    extra = parseTrailing(resource, Constants.RESOURCE_REPLICATION_DELETE_REPLICA);
366
                    deleteReplica(extra);
367
                    status = true;
368
                }
369

    
370
                if (!status) {
371
                    throw new ServiceFailure("0000", "Unknown error, status = "
372
                            + status);
373
                }
374
            } else {
375
                throw new InvalidRequest("0000", "No resource matched for "
376
                        + resource);
377
            }
378
        } catch (BaseException be) {
379
            // report Exceptions as clearly and generically as possible
380
            OutputStream out = null;
381
            try {
382
                out = response.getOutputStream();
383
            } catch (IOException ioe) {
384
                logMetacat.error("Could not get output stream from response",
385
                        ioe);
386
            }
387
            serializeException(be, out);
388
        } catch (Exception e) {
389
            // report Exceptions as clearly and generically as possible
390
            logMetacat.error(e.getClass() + ": " + e.getMessage(), e);
391
            OutputStream out = null;
392
            try {
393
                out = response.getOutputStream();
394
            } catch (IOException ioe) {
395
                logMetacat.error("Could not get output stream from response",
396
                        ioe);
397
            }
398
            ServiceFailure se = new ServiceFailure("0000", e.getMessage());
399
            serializeException(se, out);
400
        }
401
    }
402

    
403
    /**
404
     * Get the checksum for the given guid
405
     * 
406
     * @param guid
407
     * @throws NotImplemented
408
     * @throws InvalidRequest
409
     * @throws NotFound
410
     * @throws NotAuthorized
411
     * @throws ServiceFailure
412
     * @throws InvalidToken
413
     * @throws IOException
414
     * @throws JiBXException
415
     */
416
    private void checksum(String guid) throws InvalidToken, ServiceFailure,
417
            NotAuthorized, NotFound, InvalidRequest, NotImplemented,
418
            JiBXException, IOException {
419
        Identifier guidid = new Identifier();
420
        guidid.setValue(guid);
421
        logMetacat.debug("getting checksum for object " + guid);
422
        Checksum c = CNodeService.getInstance(request).getChecksum(session,
423
                guidid);
424
        logMetacat.debug("got checksum " + c.getValue());
425
        response.setStatus(200);
426
        logMetacat.debug("serializing response");
427
        TypeMarshaller.marshalTypeToOutputStream(c, response.getOutputStream());
428
        logMetacat.debug("done serializing response.");
429

    
430
    }
431

    
432
    /**
433
     * get the logs based on passed params. Available params are token,
434
     * fromDate, toDate, event. See
435
     * http://mule1.dataone.org/ArchitectureDocs/mn_api_crud
436
     * .html#MN_crud.getLogRecords for more info
437
     * 
438
     * @throws NotImplemented
439
     * @throws InvalidRequest
440
     * @throws NotAuthorized
441
     * @throws ServiceFailure
442
     * @throws InvalidToken
443
     * @throws IOException
444
     * @throws JiBXException
445
     */
446
    private void getLog() throws InvalidToken, ServiceFailure, NotAuthorized,
447
            InvalidRequest, NotImplemented, IOException, JiBXException {
448

    
449
        Date fromDate = null;
450
        Date toDate = null;
451
        Event event = null;
452
        Integer start = null;
453
        Integer count = null;
454

    
455
        try {
456
            String fromDateS = params.get("fromDate")[0];
457
            logMetacat.debug("param fromDateS: " + fromDateS);
458
            fromDate = DateTimeMarshaller.deserializeDateToUTC(fromDateS);
459
        } catch (Exception e) {
460
            logMetacat.warn("Could not parse fromDate: " + e.getMessage());
461
        }
462
        try {
463
            String toDateS = params.get("toDate")[0];
464
            logMetacat.debug("param toDateS: " + toDateS);
465
            toDate = DateTimeMarshaller.deserializeDateToUTC(toDateS);
466
        } catch (Exception e) {
467
            logMetacat.warn("Could not parse toDate: " + e.getMessage());
468
        }
469
        try {
470
            String eventS = params.get("event")[0];
471
            event = Event.convert(eventS);
472
        } catch (Exception e) {
473
            logMetacat.warn("Could not parse event: " + e.getMessage());
474
        }
475
        logMetacat.debug("fromDate: " + fromDate + " toDate: " + toDate);
476

    
477
        try {
478
            start = Integer.parseInt(params.get("start")[0]);
479
        } catch (Exception e) {
480
            logMetacat.warn("Could not parse start: " + e.getMessage());
481
        }
482
        try {
483
            count = Integer.parseInt(params.get("count")[0]);
484
        } catch (Exception e) {
485
            logMetacat.warn("Could not parse count: " + e.getMessage());
486
        }
487

    
488
        logMetacat.debug("calling getLogRecords");
489
        Log log = CNodeService.getInstance(request).getLogRecords(session,
490
                fromDate, toDate, event, start, count);
491

    
492
        OutputStream out = response.getOutputStream();
493
        response.setStatus(200);
494
        response.setContentType("text/xml");
495

    
496
        TypeMarshaller.marshalTypeToOutputStream(log, out);
497

    
498
    }
499

    
500
    /**
501
     * Implements REST version of DataONE CRUD API --> get
502
     * 
503
     * @param guid
504
     *            ID of data object to be read
505
     * @throws NotImplemented
506
     * @throws InvalidRequest
507
     * @throws NotFound
508
     * @throws NotAuthorized
509
     * @throws ServiceFailure
510
     * @throws InvalidToken
511
     * @throws IOException
512
     */
513
    protected void getObject(String guid) throws InvalidToken, ServiceFailure,
514
            NotAuthorized, NotFound, InvalidRequest, NotImplemented,
515
            IOException {
516

    
517
        Identifier id = new Identifier();
518
        id.setValue(guid);
519

    
520
        SystemMetadata sm = CNodeService.getInstance(request)
521
                .getSystemMetadata(session, id);
522

    
523
        // set the content type
524
        if (sm.getFormatId()
525
                .getValue()
526
                .trim()
527
                .equals(ObjectFormatCache.getInstance().getFormat("text/csv")
528
                        .getFormatId().getValue())) {
529
            response.setContentType("text/csv");
530
            response.setHeader("Content-Disposition",
531
                    "inline; filename=" + id.getValue() + ".csv");
532
        } else if (sm
533
                .getFormatId()
534
                .getValue()
535
                .trim()
536
                .equals(ObjectFormatCache.getInstance().getFormat("text/plain")
537
                        .getFormatId().getValue())) {
538
            response.setContentType("text/plain");
539
            response.setHeader("Content-Disposition",
540
                    "inline; filename=" + id.getValue() + ".txt");
541
        } else if (sm
542
                .getFormatId()
543
                .getValue()
544
                .trim()
545
                .equals(ObjectFormatCache.getInstance()
546
                        .getFormat("application/octet-stream").getFormatId()
547
                        .getValue())) {
548
            response.setContentType("application/octet-stream");
549
        } else {
550
            response.setContentType("text/xml");
551
            response.setHeader("Content-Disposition",
552
                    "inline; filename=" + id.getValue() + ".xml");
553
        }
554

    
555
        InputStream data = CNodeService.getInstance(request).get(session, id);
556

    
557
        OutputStream out = response.getOutputStream();
558
        response.setStatus(200);
559
        IOUtils.copyLarge(data, out);
560

    
561
    }
562

    
563
    /**
564
     * Implements REST version of DataONE CRUD API --> getSystemMetadata
565
     * 
566
     * @param guid
567
     *            ID of data object to be read
568
     * @throws NotImplemented
569
     * @throws InvalidRequest
570
     * @throws NotFound
571
     * @throws NotAuthorized
572
     * @throws ServiceFailure
573
     * @throws InvalidToken
574
     * @throws IOException
575
     * @throws JiBXException
576
     */
577
    protected void getSystemMetadataObject(String guid) throws InvalidToken,
578
            ServiceFailure, NotAuthorized, NotFound, InvalidRequest,
579
            NotImplemented, IOException, JiBXException {
580

    
581
        Identifier id = new Identifier();
582
        id.setValue(guid);
583
        SystemMetadata sysmeta = CNodeService.getInstance(request)
584
                .getSystemMetadata(session, id);
585

    
586
        response.setContentType("text/xml");
587
        response.setStatus(200);
588
        OutputStream out = response.getOutputStream();
589

    
590
        // Serialize and write it to the output stream
591
        TypeMarshaller.marshalTypeToOutputStream(sysmeta, out);
592
    }
593

    
594
    /**
595
     * Earthgrid API > Put Service >Put Function : calls MetacatHandler >
596
     * handleInsertOrUpdateAction
597
     * 
598
     * @param guid
599
     *            - ID of data object to be inserted or updated. If action is
600
     *            update, the pid is the existing pid. If insert, the pid is the
601
     *            new one
602
     * @throws InvalidRequest
603
     * @throws ServiceFailure
604
     * @throws IdentifierNotUnique
605
     * @throws JiBXException
606
     * @throws NotImplemented
607
     * @throws InvalidSystemMetadata
608
     * @throws InsufficientResources
609
     * @throws UnsupportedType
610
     * @throws NotAuthorized
611
     * @throws InvalidToken
612
     * @throws IOException
613
     * @throws IllegalAccessException
614
     * @throws InstantiationException
615
     */
616
    protected void putObject(String action) throws ServiceFailure,
617
            InvalidRequest, IdentifierNotUnique, JiBXException, InvalidToken,
618
            NotAuthorized, UnsupportedType, InsufficientResources,
619
            InvalidSystemMetadata, NotImplemented, IOException,
620
            InstantiationException, IllegalAccessException {
621
    	
622
        // Read the incoming data from its Mime Multipart encoding
623
        Map<String, File> files = collectMultipartFiles();
624
        
625
	    // get the encoded pid string from the body and make the object
626
        String pidString = multipartparams.get("pid").get(0);
627
        Identifier pid = new Identifier();
628
        pid.setValue(pidString);
629
        
630
        logMetacat.debug("putObject: " + pid.getValue() + "/" + action);
631
        
632
        InputStream object = null;
633
        InputStream sysmeta = null;
634

    
635
        File smFile = files.get("sysmeta");
636
        sysmeta = new FileInputStream(smFile);
637
        File objFile = files.get("object");
638
        object = new FileInputStream(objFile);
639

    
640
        if (action.equals(FUNCTION_NAME_INSERT)) { // handle inserts
641

    
642
            logMetacat.debug("Commence creation...");
643
            SystemMetadata smd = TypeMarshaller.unmarshalTypeFromStream(
644
                    SystemMetadata.class, sysmeta);
645

    
646
           
647
            logMetacat.debug("creating object with pid " + pid.getValue());
648
            Identifier rId = CNodeService.getInstance(request).create(session, pid, object, smd);
649

    
650
            OutputStream out = response.getOutputStream();
651
            response.setStatus(200);
652
            response.setContentType("text/xml");
653

    
654
            TypeMarshaller.marshalTypeToOutputStream(rId, out);
655

    
656
        } else {
657
            throw new InvalidRequest("1000", "Operation must be create.");
658
        }
659
    }
660

    
661
    /**
662
     * List the object formats registered with the system
663
     * 
664
     * @throws NotImplemented
665
     * @throws InsufficientResources
666
     * @throws NotFound
667
     * @throws ServiceFailure
668
     * @throws InvalidRequest
669
     * @throws IOException
670
     * @throws JiBXException
671
     */
672
    private void listFormats() throws InvalidRequest, ServiceFailure, NotFound,
673
            InsufficientResources, NotImplemented, IOException, JiBXException {
674
        logMetacat.debug("Entering listFormats()");
675

    
676
        ObjectFormatList objectFormatList = CNodeService.getInstance(request)
677
                .listFormats();
678
        // get the response output stream
679
        OutputStream out = response.getOutputStream();
680
        response.setStatus(200);
681
        response.setContentType("text/xml");
682

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

    
692
        TypeMarshaller.marshalTypeToOutputStream(objectFormatList, out,
693
                stylesheet);
694

    
695
    }
696
    
697
    private void listChecksumAlgorithms() throws IOException, ServiceFailure,
698
			NotImplemented, JiBXException {
699
		logMetacat.debug("Entering listFormats()");
700

    
701
		ChecksumAlgorithmList result = CNodeService.getInstance(request).listChecksumAlgorithms();
702

    
703
		// get the response output stream
704
		OutputStream out = response.getOutputStream();
705
		response.setStatus(200);
706
		response.setContentType("text/xml");
707

    
708
		TypeMarshaller.marshalTypeToOutputStream(result, out);
709

    
710
	}
711
    
712
    /**
713
     * http://mule1.dataone.org/ArchitectureDocs-current/apis/CN_APIs.html#CNRead.describe
714
     * @param pid
715
     * @throws InvalidToken
716
     * @throws ServiceFailure
717
     * @throws NotAuthorized
718
     * @throws NotFound
719
     * @throws NotImplemented
720
     * @throws InvalidRequest
721
     */
722
    private void describeObject(String pid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, InvalidRequest
723
    {
724
        response.setContentType("text/xml");
725
        
726
        Identifier id = new Identifier();
727
        id.setValue(pid);
728
        
729
        DescribeResponse dr = null;
730
        try {
731
            dr = CNodeService.getInstance(request).describe(session, id);
732
        } catch (BaseException e) {
733
        	response.setStatus(e.getCode());
734
        	response.addHeader("DataONE-Exception-Name", e.getClass().getName());
735
            response.addHeader("DataONE-Exception-DetailCode", e.getDetail_code());
736
            response.addHeader("DataONE-Exception-Description", e.getDescription());
737
            response.addHeader("DataONE-Exception-PID", id.getValue());
738
            return;
739
		}
740
        
741
        response.setStatus(200);
742
        //response.addHeader("pid", pid);
743
        response.addHeader("DataONE-Checksum", dr.getDataONE_Checksum().getAlgorithm() + "," + dr.getDataONE_Checksum().getValue());
744
        response.addHeader("Content-Length", dr.getContent_Length() + "");
745
        response.addHeader("Last-Modified", DateTimeMarshaller.serializeDateToUTC(dr.getLast_Modified()));
746
        response.addHeader("DataONE-ObjectFormat", dr.getDataONE_ObjectFormatIdentifier().getValue());
747
        response.addHeader("DataONE-SerialVersion", dr.getSerialVersion().toString());
748

    
749
    }
750

    
751
    /**
752
     * Return the requested object format
753
     * 
754
     * @param fmtidStr
755
     *            the requested format identifier as a string
756
     * @throws NotImplemented
757
     * @throws InsufficientResources
758
     * @throws NotFound
759
     * @throws ServiceFailure
760
     * @throws InvalidRequest
761
     * @throws IOException
762
     * @throws JiBXException
763
     */
764
    private void getFormat(String fmtidStr) throws InvalidRequest,
765
            ServiceFailure, NotFound, InsufficientResources, NotImplemented,
766
            IOException, JiBXException {
767
        logMetacat.debug("Entering listFormats()");
768

    
769
        ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
770
        fmtid.setValue(fmtidStr);
771

    
772
        // get the specified object format
773
        ObjectFormat objectFormat = CNodeService.getInstance(request)
774
                .getFormat(fmtid);
775

    
776
        OutputStream out = response.getOutputStream();
777
        response.setStatus(200);
778
        response.setContentType("text/xml");
779

    
780
        TypeMarshaller.marshalTypeToOutputStream(objectFormat, out);
781

    
782
    }
783

    
784
    /**
785
     * Reserve the given Identifier
786
     * 
787
     * @throws InvalidToken
788
     * @throws ServiceFailure
789
     * @throws NotAuthorized
790
     * @throws IdentifierNotUnique
791
     * @throws NotImplemented
792
     * @throws InvalidRequest
793
     * @throws IOException
794
     * @throws JiBXException
795
     */
796
    private void reserve() throws InvalidToken, ServiceFailure, NotAuthorized,
797
            IdentifierNotUnique, NotImplemented, InvalidRequest, IOException,
798
            JiBXException {
799
        Identifier pid = null;
800
        String scope = null;
801
        String format = null;
802
        // gather the params
803
        try {
804
            String id = params.get("pid")[0];
805
            pid = new Identifier();
806
            pid.setValue(id);
807
        } catch (Exception e) {
808
            logMetacat.warn("pid not specified");
809
        }
810
        try {
811
            scope = params.get("scope")[0];
812
        } catch (Exception e) {
813
            logMetacat.warn("pid not specified");
814
        }
815
        try {
816
            format = params.get("format")[0];
817
        } catch (Exception e) {
818
            logMetacat.warn("pid not specified");
819
        }
820
        // call the implementation
821
        Identifier resultPid = CNodeService.getInstance(request)
822
                .reserveIdentifier(session, pid);
823
        OutputStream out = response.getOutputStream();
824
        response.setStatus(200);
825
        response.setContentType("text/xml");
826
        // send back the reserved pid
827
        TypeMarshaller.marshalTypeToOutputStream(resultPid, out);
828
    }
829

    
830
    /**
831
     * 
832
     * @param id
833
     * @throws InvalidRequest
834
     * @throws InvalidToken
835
     * @throws ServiceFailure
836
     * @throws NotAuthorized
837
     * @throws NotFound
838
     * @throws NotImplemented
839
     * @throws IOException
840
     * @throws JiBXException
841
     */
842
    private void resolve(String id) throws InvalidRequest, InvalidToken,
843
            ServiceFailure, NotAuthorized, NotFound, NotImplemented,
844
            IOException, JiBXException {
845
        Identifier pid = new Identifier();
846
        pid.setValue(id);
847
        ObjectLocationList locationList = CNodeService.getInstance(request)
848
                .resolve(session, pid);
849
        OutputStream out = response.getOutputStream();
850
        response.setStatus(200);
851
        response.setContentType("text/xml");
852
        TypeMarshaller.marshalTypeToOutputStream(locationList, out);
853

    
854
    }
855

    
856
    /**
857
     * Set the owner of a resource
858
     * 
859
     * @param id
860
     * @throws JiBXException
861
     * @throws InvalidToken
862
     * @throws ServiceFailure
863
     * @throws NotFound
864
     * @throws NotAuthorized
865
     * @throws NotImplemented
866
     * @throws InvalidRequest
867
     * @throws IOException
868
     * @throws IllegalAccessException
869
     * @throws InstantiationException
870
     * @throws VersionMismatch 
871
     */
872
    private void owner(String id) throws JiBXException, InvalidToken,
873
            ServiceFailure, NotFound, NotAuthorized, NotImplemented,
874
            InvalidRequest, IOException, InstantiationException,
875
            IllegalAccessException, VersionMismatch {
876

    
877
        Identifier pid = new Identifier();
878
        pid.setValue(id);
879

    
880
        long serialVersion = 0L;
881
        String serialVersionStr = null;
882

    
883
        // get the serialVersion
884
        try {
885
            serialVersionStr = params.get("serialVersion")[0];
886
            serialVersion = new Long(serialVersionStr).longValue();
887

    
888
        } catch (NullPointerException e) {
889
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
890
            logMetacat.error(msg);
891
            throw new InvalidRequest("4442", msg);
892

    
893
        }
894

    
895
        // get the subject
896
        String subjectStr = params.get("subject")[0];
897
        Subject subject = TypeMarshaller.unmarshalTypeFromStream(Subject.class,
898
                new ByteArrayInputStream(subjectStr.getBytes("UTF-8")));
899

    
900
        Identifier retPid = CNodeService.getInstance(request).setRightsHolder(session, pid, subject, serialVersion);
901
        OutputStream out = response.getOutputStream();
902
        response.setStatus(200);
903
        response.setContentType("text/xml");
904
        TypeMarshaller.marshalTypeToOutputStream(retPid, out);
905
    }
906

    
907
    /**
908
     * Processes the authorization check for given id
909
     * 
910
     * @param id
911
     * @return
912
     * @throws ServiceFailure
913
     * @throws InvalidToken
914
     * @throws NotFound
915
     * @throws NotAuthorized
916
     * @throws NotImplemented
917
     * @throws InvalidRequest
918
     */
919
    private boolean isAuthorized(String id) throws ServiceFailure,
920
            InvalidToken, NotFound, NotAuthorized, NotImplemented,
921
            InvalidRequest {
922
        Identifier pid = new Identifier();
923
        pid.setValue(id);
924
        String permission = params.get("action")[0];
925
        boolean result = CNodeService.getInstance(request).isAuthorized(
926
                session, pid, Permission.convert(permission));
927
        response.setStatus(200);
928
        response.setContentType("text/xml");
929
        return result;
930
    }
931

    
932
    /**
933
     * Register System Metadata without data or metadata object
934
     * 
935
     * @param pid
936
     *            identifier for System Metadata entry
937
     * @throws JiBXException
938
     * @throws FileUploadException
939
     * @throws IOException
940
     * @throws InvalidRequest
941
     * @throws ServiceFailure
942
     * @throws InvalidSystemMetadata
943
     * @throws NotAuthorized
944
     * @throws NotImplemented
945
     * @throws IllegalAccessException
946
     * @throws InstantiationException
947
     */
948
    protected void registerSystemMetadata()
949
            throws ServiceFailure, InvalidRequest, IOException,
950
            FileUploadException, JiBXException, NotImplemented, NotAuthorized,
951
            InvalidSystemMetadata, InstantiationException,
952
            IllegalAccessException {
953
    	
954
    	// Read the incoming data from its Mime Multipart encoding
955
        Map<String, File> files = collectMultipartFiles();
956
        
957
    	// get the encoded pid string from the body and make the object
958
        String pidString = multipartparams.get("pid").get(0);
959
        Identifier pid = new Identifier();
960
        pid.setValue(pidString);
961
        
962
        logMetacat.debug("registerSystemMetadata: " + pid);
963

    
964
        // get the system metadata from the request
965
        File smFile = files.get("sysmeta");
966
        FileInputStream sysmeta = new FileInputStream(smFile);
967
        SystemMetadata systemMetadata = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysmeta);
968

    
969
        logMetacat.debug("registering system metadata with pid " + pid.getValue());
970
        Identifier retGuid = CNodeService.getInstance(request).registerSystemMetadata(session, pid, systemMetadata);
971

    
972
        OutputStream out = response.getOutputStream();
973
        response.setStatus(200);
974
        response.setContentType("text/xml");
975
        
976
        TypeMarshaller.marshalTypeToOutputStream(retGuid, out);
977

    
978
    }
979

    
980
    /**
981
     * set the access perms on a document
982
     * 
983
     * @throws JiBXException
984
     * @throws InvalidRequest
985
     * @throws NotImplemented
986
     * @throws NotAuthorized
987
     * @throws NotFound
988
     * @throws ServiceFailure
989
     * @throws InvalidToken
990
     * @throws IllegalAccessException
991
     * @throws InstantiationException
992
     * @throws IOException
993
     * @throws SAXException
994
     * @throws ParserConfigurationException
995
     * @throws VersionMismatch 
996
     */
997
    protected void setAccess(String pid) throws JiBXException, InvalidToken,
998
            ServiceFailure, NotFound, NotAuthorized, NotImplemented,
999
            InvalidRequest, IOException, InstantiationException,
1000
            IllegalAccessException, ParserConfigurationException, SAXException, VersionMismatch {
1001

    
1002
        long serialVersion = 0L;
1003
        String serialVersionStr = null;
1004

    
1005
        // get the serialVersion
1006
        try {
1007
            serialVersionStr = params.get("serialVersion")[0];
1008
            serialVersion = new Long(serialVersionStr).longValue();
1009

    
1010
        } catch (NullPointerException e) {
1011
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1012
            logMetacat.error(msg);
1013
            throw new InvalidRequest("4402", msg);
1014

    
1015
        }
1016

    
1017
        Identifier id = new Identifier();
1018
        id.setValue(pid);
1019

    
1020
        AccessPolicy accessPolicy = collectAccessPolicy();
1021
        CNodeService.getInstance(request).setAccessPolicy(session, id,
1022
                accessPolicy, serialVersion);
1023

    
1024
    }
1025

    
1026
    /**
1027
     * List the objects
1028
     * 
1029
     * @throws NotImplemented
1030
     * @throws InvalidRequest
1031
     * @throws NotAuthorized
1032
     * @throws ServiceFailure
1033
     * @throws InvalidToken
1034
     * @throws NotFound
1035
     * @throws IOException
1036
     * @throws JiBXException
1037
     * @throws Exception
1038
     */
1039
    private void listObjects() throws InvalidToken, ServiceFailure,
1040
            NotAuthorized, InvalidRequest, NotImplemented, NotFound,
1041
            IOException, JiBXException {
1042

    
1043
        Date startTime = null;
1044
        Date endTime = null;
1045
        ObjectFormatIdentifier fmtid = null;
1046
        boolean replicaStatus = false;
1047
        int start = 0;
1048
        int count = -1;
1049
        Enumeration<String> paramlist = request.getParameterNames();
1050
        while (paramlist.hasMoreElements()) {
1051
            // parse the params and make the call
1052
            String name = paramlist.nextElement();
1053
            String[] values = request.getParameterValues(name);
1054
            String value = null;
1055
            if (values != null && values.length > 0) {
1056
            	value = values[0];
1057
            	value = EncodingUtilities.decodeString(value);
1058
            }
1059

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

    
1093
        // get the list
1094
        ObjectList ol = CNodeService.getInstance(request).listObjects(session,
1095
                startTime, endTime, fmtid, replicaStatus, start, count);
1096

    
1097
        // send it
1098
        OutputStream out = response.getOutputStream();
1099
        response.setStatus(200);
1100
        response.setContentType("text/xml");
1101

    
1102
        // style the object with a processing directive
1103
        String stylesheet = null;
1104
        try {
1105
            stylesheet = PropertyService.getProperty("dataone.types.xsl");
1106
        } catch (PropertyNotFoundException e) {
1107
            logMetacat.warn("Could not locate DataONE types XSLT: "
1108
                    + e.getMessage());
1109
        }
1110

    
1111
        // Serialize and write it to the output stream
1112
        TypeMarshaller.marshalTypeToOutputStream(ol, out, stylesheet);
1113
    }
1114

    
1115
    /**
1116
     * Pass the request to get node replication authorization to CNodeService
1117
     * 
1118
     * @param pid
1119
     *            the identifier of the object to get authorization to replicate
1120
     * 
1121
     * @throws NotImplemented
1122
     * @throws NotAuthorized
1123
     * @throws InvalidToken
1124
     * @throws ServiceFailure
1125
     * @throws NotFound
1126
     * @throws InvalidRequest
1127
     */
1128
    public boolean isNodeAuthorized(String pid) throws NotImplemented,
1129
            NotAuthorized, InvalidToken, ServiceFailure, NotFound,
1130
            InvalidRequest {
1131

    
1132
        boolean result = false;
1133
        Subject targetNodeSubject = new Subject();
1134
        String nodeSubject = null;
1135
        String replPermission = null;
1136

    
1137
        // get the pid
1138
        Identifier identifier = new Identifier();
1139
        identifier.setValue(pid);
1140

    
1141
        // get the target node subject
1142
        try {
1143
            nodeSubject = params.get("targetNodeSubject")[0];
1144
            targetNodeSubject.setValue(nodeSubject);
1145

    
1146
        } catch (NullPointerException e) {
1147
            String msg = "The 'targetNodeSubject' must be provided as a parameter and was not.";
1148
            logMetacat.error(msg);
1149
            throw new InvalidRequest("4873", msg);
1150

    
1151
        }
1152

    
1153
        result = CNodeService.getInstance(request).isNodeAuthorized(session, targetNodeSubject, identifier);
1154

    
1155
        response.setStatus(200);
1156
        response.setContentType("text/xml");
1157
        return result;
1158

    
1159
    }
1160

    
1161
    /**
1162
     * Pass the request to set the replication policy to CNodeService
1163
     * 
1164
     * @param pid
1165
     *            the identifier of the object to set the replication policy on
1166
     * 
1167
     * @throws NotImplemented
1168
     * @throws NotFound
1169
     * @throws NotAuthorized
1170
     * @throws ServiceFailure
1171
     * @throws InvalidRequest
1172
     * @throws InvalidToken
1173
     * @throws IOException
1174
     * @throws InstantiationException
1175
     * @throws IllegalAccessException
1176
     * @throws JiBXException
1177
     * @throws VersionMismatch 
1178
     */
1179
    public boolean setReplicationPolicy(String pid) throws NotImplemented,
1180
            NotFound, NotAuthorized, ServiceFailure, InvalidRequest,
1181
            InvalidToken, IOException, InstantiationException,
1182
            IllegalAccessException, JiBXException, VersionMismatch {
1183

    
1184
        boolean result = false;
1185
        ReplicationPolicy policy = null;
1186
        long serialVersion = 0L;
1187
        String serialVersionStr = null;
1188

    
1189
        Identifier identifier = new Identifier();
1190
        identifier.setValue(pid);
1191

    
1192
        policy = collectReplicationPolicy();
1193

    
1194
        // get the serialVersion
1195
        try {
1196
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1197
            serialVersion = new Long(serialVersionStr).longValue();
1198

    
1199
        } catch (NullPointerException e) {
1200
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1201
            logMetacat.error(msg);
1202
            throw new InvalidRequest("4883", msg);
1203

    
1204
        }
1205
        result = CNodeService.getInstance(request).setReplicationPolicy(
1206
                session, identifier, policy, serialVersion);
1207
        response.setStatus(200);
1208
        response.setContentType("text/xml");
1209
        return result;
1210

    
1211
    }
1212
    
1213
    public boolean setObsoletedBy(String pid) throws NotImplemented,
1214
	    NotFound, NotAuthorized, ServiceFailure, InvalidRequest,
1215
	    InvalidToken, IOException, InstantiationException,
1216
	    IllegalAccessException, JiBXException, VersionMismatch {
1217
	
1218
		boolean result = false;
1219
		long serialVersion = 0L;
1220
		String serialVersionStr = null;
1221
		
1222
		Identifier identifier = new Identifier();
1223
		identifier.setValue(pid);
1224
		
1225
		Identifier obsoletedByPid = null;
1226
		try {
1227
			String obsoletedByPidString = params.get("obsoletedByPid")[0];
1228
			obsoletedByPid = new Identifier();
1229
			obsoletedByPid.setValue(obsoletedByPidString);
1230
		} catch (NullPointerException e) {
1231
		    String msg = "The 'obsoletedByPid' must be provided as a parameter and was not.";
1232
		    logMetacat.error(msg);
1233
		    throw new InvalidRequest("4883", msg);
1234
		}
1235
		
1236
		// get the serialVersion
1237
		try {
1238
		    serialVersionStr = params.get("serialVersion")[0];
1239
		    serialVersion = new Long(serialVersionStr).longValue();
1240
		
1241
		} catch (NullPointerException e) {
1242
		    String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1243
		    logMetacat.error(msg);
1244
		    throw new InvalidRequest("4883", msg);
1245
		
1246
		}
1247
		result = CNodeService.getInstance(request).setObsoletedBy(
1248
		        session, identifier, obsoletedByPid, serialVersion);
1249
		response.setStatus(200);
1250
		response.setContentType("text/xml");
1251
		return result;
1252
	
1253
	}
1254
    
1255
    public boolean deleteReplica(String pid) throws NotImplemented, NotFound,
1256
			NotAuthorized, ServiceFailure, InvalidRequest, InvalidToken,
1257
			IOException, InstantiationException, IllegalAccessException,
1258
			JiBXException, VersionMismatch {
1259

    
1260
		boolean result = false;
1261
		long serialVersion = 0L;
1262
		String serialVersionStr = null;
1263

    
1264
		Identifier identifier = new Identifier();
1265
		identifier.setValue(pid);
1266

    
1267
		NodeReference nodeId = null;
1268
		try {
1269
			String nodeIdString = params.get("nodeId")[0];
1270
			nodeId = new NodeReference();
1271
			nodeId.setValue(nodeIdString);
1272
		} catch (NullPointerException e) {
1273
			String msg = "The 'nodeId' must be provided as a parameter and was not.";
1274
			logMetacat.error(msg);
1275
			throw new InvalidRequest("4883", msg);
1276
		}
1277

    
1278
		// get the serialVersion
1279
		try {
1280
			serialVersionStr = params.get("serialVersion")[0];
1281
			serialVersion = new Long(serialVersionStr).longValue();
1282

    
1283
		} catch (NullPointerException e) {
1284
			String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1285
			logMetacat.error(msg);
1286
			throw new InvalidRequest("4883", msg);
1287

    
1288
		}
1289
		result = CNodeService.getInstance(request).deleteReplicationMetadata(session, identifier, nodeId, serialVersion);
1290
		response.setStatus(200);
1291
		response.setContentType("text/xml");
1292
		return result;
1293

    
1294
	}
1295

    
1296
    /**
1297
     * Pass the request to set the replication status to CNodeService
1298
     * 
1299
     * @param pid
1300
     *            the identifier of the object to set the replication status on
1301
     * 
1302
     * @throws ServiceFailure
1303
     * @throws NotImplemented
1304
     * @throws InvalidToken
1305
     * @throws NotAuthorized
1306
     * @throws InvalidRequest
1307
     * @throws NotFound
1308
     * @throws JiBXException 
1309
     * @throws IllegalAccessException 
1310
     * @throws InstantiationException 
1311
     * @throws IOException 
1312
     */
1313
    public boolean setReplicationStatus(String pid) throws ServiceFailure,
1314
            NotImplemented, InvalidToken, NotAuthorized, InvalidRequest,
1315
            NotFound {
1316
        
1317
        boolean result = false;
1318
        Identifier identifier = new Identifier();
1319
        identifier.setValue(pid);
1320
        BaseException failure = null;
1321
        ReplicationStatus status = null;
1322
        String replicationStatus = null;
1323
        NodeReference targetNodeRef = null;
1324
        String targetNode = null;
1325

    
1326
        // Parse the params out of the multipart form data
1327
        // Read the incoming data from its Mime Multipart encoding
1328
        logMetacat.debug("Parsing ReplicaStatus from the mime multipart entity");
1329

    
1330
        try {
1331
            failure = collectReplicationStatus();
1332
            
1333
        } catch (IOException e2) {
1334
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1335
                e2.getMessage());
1336
            
1337
        } catch (InstantiationException e2) {
1338
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1339
                e2.getMessage());
1340
            
1341
        } catch (IllegalAccessException e2) {
1342
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1343
                    e2.getMessage());
1344
            
1345
        } catch (JiBXException e2) {
1346
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1347
                    e2.getMessage());
1348
            
1349
        }
1350
        
1351
        // get the replication status param
1352
        try {
1353
            replicationStatus = multipartparams.get("status").get(0);
1354
            status = ReplicationStatus.convert(replicationStatus);
1355

    
1356
        } catch (NullPointerException npe) {
1357

    
1358
            logMetacat.debug("The 'status' parameter was not found in the "
1359
                    + "multipartparams map.  Trying the params map.");
1360

    
1361
            try {
1362
                replicationStatus = params.get("status")[0];
1363
                status = ReplicationStatus.convert(replicationStatus
1364
                        .toLowerCase());
1365

    
1366
            } catch (Exception e) {
1367
                String msg = "The 'status' must be provided as a parameter and was not.";
1368
                logMetacat.error(msg);
1369
                throw new InvalidRequest("4730", msg);
1370

    
1371
            }
1372

    
1373
        }
1374

    
1375
        // get the target node reference param
1376
        try {
1377
            targetNode = multipartparams.get("nodeRef").get(0);
1378
            targetNodeRef = new NodeReference();
1379
            targetNodeRef.setValue(targetNode);
1380

    
1381
        } catch (NullPointerException e) {
1382
            logMetacat.debug("The 'nodeRef' parameter was not found in the "
1383
                    + "multipartparams map.  Trying the params map.");
1384

    
1385
            try {
1386
                targetNode = params.get("nodeRef")[0];
1387
                targetNodeRef = new NodeReference();
1388
                targetNodeRef.setValue(targetNode);
1389

    
1390
            } catch (Exception e1) {
1391
                String msg = "The 'nodeRef' must be provided as a parameter and was not.";
1392
                logMetacat.error(msg);
1393
                throw new InvalidRequest("4730", msg);
1394

    
1395
            }
1396

    
1397
        }
1398

    
1399
        result = CNodeService.getInstance(request).setReplicationStatus(
1400
                session, identifier, targetNodeRef, status, failure);
1401
        response.setStatus(200);
1402
        response.setContentType("text/xml");
1403
        return result;
1404

    
1405
    }
1406

    
1407
    /**
1408
     * Pass the request to update the replication metadata to CNodeService
1409
     * 
1410
     * @param pid
1411
     *            the identifier of the object to update the replication
1412
     *            metadata on
1413
     * 
1414
     * @throws ServiceFailure
1415
     * @throws NotImplemented
1416
     * @throws InvalidToken
1417
     * @throws NotAuthorized
1418
     * @throws InvalidRequest
1419
     * @throws NotFound
1420
     * @throws VersionMismatch 
1421
     */
1422
    public boolean updateReplicationMetadata(String pid) throws ServiceFailure,
1423
            NotImplemented, InvalidToken, NotAuthorized, InvalidRequest,
1424
            NotFound, VersionMismatch {
1425

    
1426
        boolean result = false;
1427
        long serialVersion = 0L;
1428
        String serialVersionStr = null;
1429
        Replica replica = null;
1430
        Identifier identifier = new Identifier();
1431
        identifier.setValue(pid);
1432

    
1433
        replica = collectReplicaMetadata();
1434

    
1435
        // get the serialVersion
1436
        try {
1437
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1438
            serialVersion = new Long(serialVersionStr).longValue();
1439

    
1440
        } catch (NullPointerException e) {
1441
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1442
            logMetacat.error(msg);
1443
            throw new InvalidRequest("4853", msg);
1444

    
1445
        }
1446

    
1447
        result = CNodeService.getInstance(request).updateReplicationMetadata(
1448
                session, identifier, replica, serialVersion);
1449
        response.setStatus(200);
1450
        response.setContentType("text/xml");
1451
        return result;
1452

    
1453
    }
1454

    
1455
}
(1-1/9)