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: cjones $'
7
 *     '$Date: 2012-03-26 15:11:13 -0700 (Mon, 26 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
                    } else if (httpVerb == DELETE) {
253
                        deleteObject(extra);
254
                        status = true;
255
                    } 
256

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

    
260
                    // after the command
261
                    extra = parseTrailing(resource, RESOURCE_FORMATS);
262

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

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

    
283
                } else if (resource.startsWith(Constants.RESOURCE_CHECKSUM)) {
284
                    logMetacat.debug("Using resource: " + Constants.RESOURCE_CHECKSUM);
285

    
286
                    // after the command
287
                    extra = parseTrailing(resource, Constants.RESOURCE_CHECKSUM);
288

    
289
                    // handle checksum requests
290
                    if (httpVerb == GET) {
291

    
292
                    	if (extra != null && extra.length() > 0) {
293
	                        checksum(extra);
294
	                        status = true;
295
                    	} else {
296
                    		listChecksumAlgorithms();
297
                    		status = true;
298
                    	}
299

    
300
                    }
301

    
302
                } else if (resource.startsWith(RESOURCE_REPLICATION_POLICY)
303
                        && httpVerb == PUT) {
304

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

    
312
                } else if (resource.startsWith(RESOURCE_REPLICATION_META)
313
                        && httpVerb == PUT) {
314

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

    
322
                } else if (resource.startsWith(RESOURCE_REPLICATION_NOTIFY)
323
                        && httpVerb == PUT) {
324

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

    
332
                } else if (resource.startsWith(RESOURCE_REPLICATION_AUTHORIZED)
333
                        && httpVerb == GET) {
334

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

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

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

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

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

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

    
433
    }
434

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

    
452
        Date fromDate = null;
453
        Date toDate = null;
454
        Event event = null;
455
        Integer start = null;
456
        Integer count = null;
457

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

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

    
491
        logMetacat.debug("calling getLogRecords");
492
        Log log = CNodeService.getInstance(request).getLogRecords(session,
493
                fromDate, toDate, event, start, count);
494

    
495
        OutputStream out = response.getOutputStream();
496
        response.setStatus(200);
497
        response.setContentType("text/xml");
498

    
499
        TypeMarshaller.marshalTypeToOutputStream(log, out);
500

    
501
    }
502

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

    
520
        Identifier id = new Identifier();
521
        id.setValue(guid);
522

    
523
        SystemMetadata sm = CNodeService.getInstance(request)
524
                .getSystemMetadata(session, id);
525

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

    
558
        InputStream data = CNodeService.getInstance(request).get(session, id);
559

    
560
        OutputStream out = response.getOutputStream();
561
        response.setStatus(200);
562
        IOUtils.copyLarge(data, out);
563

    
564
    }
565

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

    
584
        Identifier id = new Identifier();
585
        id.setValue(guid);
586
        SystemMetadata sysmeta = CNodeService.getInstance(request)
587
                .getSystemMetadata(session, id);
588

    
589
        response.setContentType("text/xml");
590
        response.setStatus(200);
591
        OutputStream out = response.getOutputStream();
592

    
593
        // Serialize and write it to the output stream
594
        TypeMarshaller.marshalTypeToOutputStream(sysmeta, out);
595
    }
596

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

    
638
        File smFile = files.get("sysmeta");
639
        sysmeta = new FileInputStream(smFile);
640
        File objFile = files.get("object");
641
        object = new FileInputStream(objFile);
642

    
643
        if (action.equals(FUNCTION_NAME_INSERT)) { // handle inserts
644

    
645
            logMetacat.debug("Commence creation...");
646
            SystemMetadata smd = TypeMarshaller.unmarshalTypeFromStream(
647
                    SystemMetadata.class, sysmeta);
648

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

    
653
            OutputStream out = response.getOutputStream();
654
            response.setStatus(200);
655
            response.setContentType("text/xml");
656

    
657
            TypeMarshaller.marshalTypeToOutputStream(rId, out);
658

    
659
        } else {
660
            throw new InvalidRequest("1000", "Operation must be create.");
661
        }
662
    }
663

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

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

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

    
695
        TypeMarshaller.marshalTypeToOutputStream(objectFormatList, out,
696
                stylesheet);
697

    
698
    }
699
    
700
    private void listChecksumAlgorithms() throws IOException, ServiceFailure,
701
			NotImplemented, JiBXException {
702
		logMetacat.debug("Entering listFormats()");
703

    
704
		ChecksumAlgorithmList result = CNodeService.getInstance(request).listChecksumAlgorithms();
705

    
706
		// get the response output stream
707
		OutputStream out = response.getOutputStream();
708
		response.setStatus(200);
709
		response.setContentType("text/xml");
710

    
711
		TypeMarshaller.marshalTypeToOutputStream(result, out);
712

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

    
752
    }
753
    
754
    /**
755
     * Handle delete 
756
     * @param pid ID of data object to be deleted
757
     * @throws IOException
758
     * @throws InvalidRequest 
759
     * @throws NotImplemented 
760
     * @throws NotFound 
761
     * @throws NotAuthorized 
762
     * @throws ServiceFailure 
763
     * @throws InvalidToken 
764
     * @throws JiBXException 
765
     */
766
    private void deleteObject(String pid) throws IOException, InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, InvalidRequest, JiBXException 
767
    {
768

    
769
        OutputStream out = response.getOutputStream();
770
        response.setStatus(200);
771
        response.setContentType("text/xml");
772

    
773
        Identifier id = new Identifier();
774
        id.setValue(pid);
775

    
776
        logMetacat.debug("Calling delete for identifier " + pid);
777
        CNodeService.getInstance(request).delete(session, id);
778
        TypeMarshaller.marshalTypeToOutputStream(id, out);
779
        
780
    }
781

    
782
    /**
783
     * Return the requested object format
784
     * 
785
     * @param fmtidStr
786
     *            the requested format identifier as a string
787
     * @throws NotImplemented
788
     * @throws InsufficientResources
789
     * @throws NotFound
790
     * @throws ServiceFailure
791
     * @throws InvalidRequest
792
     * @throws IOException
793
     * @throws JiBXException
794
     */
795
    private void getFormat(String fmtidStr) throws InvalidRequest,
796
            ServiceFailure, NotFound, InsufficientResources, NotImplemented,
797
            IOException, JiBXException {
798
        logMetacat.debug("Entering listFormats()");
799

    
800
        ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
801
        fmtid.setValue(fmtidStr);
802

    
803
        // get the specified object format
804
        ObjectFormat objectFormat = CNodeService.getInstance(request)
805
                .getFormat(fmtid);
806

    
807
        OutputStream out = response.getOutputStream();
808
        response.setStatus(200);
809
        response.setContentType("text/xml");
810

    
811
        TypeMarshaller.marshalTypeToOutputStream(objectFormat, out);
812

    
813
    }
814

    
815
    /**
816
     * Reserve the given Identifier
817
     * 
818
     * @throws InvalidToken
819
     * @throws ServiceFailure
820
     * @throws NotAuthorized
821
     * @throws IdentifierNotUnique
822
     * @throws NotImplemented
823
     * @throws InvalidRequest
824
     * @throws IOException
825
     * @throws JiBXException
826
     */
827
    private void reserve() throws InvalidToken, ServiceFailure, NotAuthorized,
828
            IdentifierNotUnique, NotImplemented, InvalidRequest, IOException,
829
            JiBXException {
830
        Identifier pid = null;
831
        String scope = null;
832
        String format = null;
833
        // gather the params
834
        try {
835
            String id = params.get("pid")[0];
836
            pid = new Identifier();
837
            pid.setValue(id);
838
        } catch (Exception e) {
839
            logMetacat.warn("pid not specified");
840
        }
841
        try {
842
            scope = params.get("scope")[0];
843
        } catch (Exception e) {
844
            logMetacat.warn("pid not specified");
845
        }
846
        try {
847
            format = params.get("format")[0];
848
        } catch (Exception e) {
849
            logMetacat.warn("pid not specified");
850
        }
851
        // call the implementation
852
        Identifier resultPid = CNodeService.getInstance(request)
853
                .reserveIdentifier(session, pid);
854
        OutputStream out = response.getOutputStream();
855
        response.setStatus(200);
856
        response.setContentType("text/xml");
857
        // send back the reserved pid
858
        TypeMarshaller.marshalTypeToOutputStream(resultPid, out);
859
    }
860

    
861
    /**
862
     * 
863
     * @param id
864
     * @throws InvalidRequest
865
     * @throws InvalidToken
866
     * @throws ServiceFailure
867
     * @throws NotAuthorized
868
     * @throws NotFound
869
     * @throws NotImplemented
870
     * @throws IOException
871
     * @throws JiBXException
872
     */
873
    private void resolve(String id) throws InvalidRequest, InvalidToken,
874
            ServiceFailure, NotAuthorized, NotFound, NotImplemented,
875
            IOException, JiBXException {
876
        Identifier pid = new Identifier();
877
        pid.setValue(id);
878
        ObjectLocationList locationList = CNodeService.getInstance(request)
879
                .resolve(session, pid);
880
        OutputStream out = response.getOutputStream();
881
        response.setStatus(200);
882
        response.setContentType("text/xml");
883
        TypeMarshaller.marshalTypeToOutputStream(locationList, out);
884

    
885
    }
886

    
887
    /**
888
     * Set the owner of a resource
889
     * 
890
     * @param id
891
     * @throws JiBXException
892
     * @throws InvalidToken
893
     * @throws ServiceFailure
894
     * @throws NotFound
895
     * @throws NotAuthorized
896
     * @throws NotImplemented
897
     * @throws InvalidRequest
898
     * @throws IOException
899
     * @throws IllegalAccessException
900
     * @throws InstantiationException
901
     * @throws VersionMismatch 
902
     */
903
    private void owner(String id) throws JiBXException, InvalidToken,
904
            ServiceFailure, NotFound, NotAuthorized, NotImplemented,
905
            InvalidRequest, IOException, InstantiationException,
906
            IllegalAccessException, VersionMismatch {
907

    
908
        Identifier pid = new Identifier();
909
        pid.setValue(id);
910

    
911
        long serialVersion = 0L;
912
        String serialVersionStr = null;
913

    
914
        // get the serialVersion
915
        try {
916
            serialVersionStr = params.get("serialVersion")[0];
917
            serialVersion = new Long(serialVersionStr).longValue();
918

    
919
        } catch (NullPointerException e) {
920
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
921
            logMetacat.error(msg);
922
            throw new InvalidRequest("4442", msg);
923

    
924
        }
925

    
926
        // get the subject
927
        String subjectStr = params.get("subject")[0];
928
        Subject subject = TypeMarshaller.unmarshalTypeFromStream(Subject.class,
929
                new ByteArrayInputStream(subjectStr.getBytes("UTF-8")));
930

    
931
        Identifier retPid = CNodeService.getInstance(request).setRightsHolder(session, pid, subject, serialVersion);
932
        OutputStream out = response.getOutputStream();
933
        response.setStatus(200);
934
        response.setContentType("text/xml");
935
        TypeMarshaller.marshalTypeToOutputStream(retPid, out);
936
    }
937

    
938
    /**
939
     * Processes the authorization check for given id
940
     * 
941
     * @param id
942
     * @return
943
     * @throws ServiceFailure
944
     * @throws InvalidToken
945
     * @throws NotFound
946
     * @throws NotAuthorized
947
     * @throws NotImplemented
948
     * @throws InvalidRequest
949
     */
950
    private boolean isAuthorized(String id) throws ServiceFailure,
951
            InvalidToken, NotFound, NotAuthorized, NotImplemented,
952
            InvalidRequest {
953
        Identifier pid = new Identifier();
954
        pid.setValue(id);
955
        String permission = params.get("action")[0];
956
        boolean result = CNodeService.getInstance(request).isAuthorized(
957
                session, pid, Permission.convert(permission));
958
        response.setStatus(200);
959
        response.setContentType("text/xml");
960
        return result;
961
    }
962

    
963
    /**
964
     * Register System Metadata without data or metadata object
965
     * 
966
     * @param pid
967
     *            identifier for System Metadata entry
968
     * @throws JiBXException
969
     * @throws FileUploadException
970
     * @throws IOException
971
     * @throws InvalidRequest
972
     * @throws ServiceFailure
973
     * @throws InvalidSystemMetadata
974
     * @throws NotAuthorized
975
     * @throws NotImplemented
976
     * @throws IllegalAccessException
977
     * @throws InstantiationException
978
     */
979
    protected void registerSystemMetadata()
980
            throws ServiceFailure, InvalidRequest, IOException,
981
            FileUploadException, JiBXException, NotImplemented, NotAuthorized,
982
            InvalidSystemMetadata, InstantiationException,
983
            IllegalAccessException {
984
    	
985
    	// Read the incoming data from its Mime Multipart encoding
986
        Map<String, File> files = collectMultipartFiles();
987
        
988
    	// get the encoded pid string from the body and make the object
989
        String pidString = multipartparams.get("pid").get(0);
990
        Identifier pid = new Identifier();
991
        pid.setValue(pidString);
992
        
993
        logMetacat.debug("registerSystemMetadata: " + pid);
994

    
995
        // get the system metadata from the request
996
        File smFile = files.get("sysmeta");
997
        FileInputStream sysmeta = new FileInputStream(smFile);
998
        SystemMetadata systemMetadata = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysmeta);
999

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

    
1003
        OutputStream out = response.getOutputStream();
1004
        response.setStatus(200);
1005
        response.setContentType("text/xml");
1006
        
1007
        TypeMarshaller.marshalTypeToOutputStream(retGuid, out);
1008

    
1009
    }
1010

    
1011
    /**
1012
     * set the access perms on a document
1013
     * 
1014
     * @throws JiBXException
1015
     * @throws InvalidRequest
1016
     * @throws NotImplemented
1017
     * @throws NotAuthorized
1018
     * @throws NotFound
1019
     * @throws ServiceFailure
1020
     * @throws InvalidToken
1021
     * @throws IllegalAccessException
1022
     * @throws InstantiationException
1023
     * @throws IOException
1024
     * @throws SAXException
1025
     * @throws ParserConfigurationException
1026
     * @throws VersionMismatch 
1027
     */
1028
    protected void setAccess(String pid) throws JiBXException, InvalidToken,
1029
            ServiceFailure, NotFound, NotAuthorized, NotImplemented,
1030
            InvalidRequest, IOException, InstantiationException,
1031
            IllegalAccessException, ParserConfigurationException, SAXException, VersionMismatch {
1032

    
1033
        long serialVersion = 0L;
1034
        String serialVersionStr = null;
1035
        AccessPolicy accessPolicy = collectAccessPolicy();
1036

    
1037
        // get the serialVersion
1038
        try {
1039
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1040
            serialVersion = new Long(serialVersionStr).longValue();
1041

    
1042
        } catch (NumberFormatException nfe) {
1043
            String msg = "The 'serialVersion' must be provided as a positive integer and was not.";
1044
            logMetacat.error(msg);
1045
            throw new InvalidRequest("4402", msg);
1046
            
1047
        } catch (NullPointerException e) {
1048
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1049
            logMetacat.error(msg);
1050
            throw new InvalidRequest("4402", msg);
1051

    
1052
        }
1053

    
1054
        Identifier id = new Identifier();
1055
        id.setValue(pid);
1056

    
1057
        CNodeService.getInstance(request).setAccessPolicy(session, id,
1058
                accessPolicy, serialVersion);
1059

    
1060
    }
1061

    
1062
    /**
1063
     * List the objects
1064
     * 
1065
     * @throws NotImplemented
1066
     * @throws InvalidRequest
1067
     * @throws NotAuthorized
1068
     * @throws ServiceFailure
1069
     * @throws InvalidToken
1070
     * @throws NotFound
1071
     * @throws IOException
1072
     * @throws JiBXException
1073
     * @throws Exception
1074
     */
1075
    private void listObjects() throws InvalidToken, ServiceFailure,
1076
            NotAuthorized, InvalidRequest, NotImplemented, NotFound,
1077
            IOException, JiBXException {
1078

    
1079
        Date startTime = null;
1080
        Date endTime = null;
1081
        ObjectFormatIdentifier fmtid = null;
1082
        boolean replicaStatus = false;
1083
        int start = 0;
1084
        int count = -1;
1085
        Enumeration<String> paramlist = request.getParameterNames();
1086
        while (paramlist.hasMoreElements()) {
1087
            // parse the params and make the call
1088
            String name = paramlist.nextElement();
1089
            String[] values = request.getParameterValues(name);
1090
            String value = null;
1091
            if (values != null && values.length > 0) {
1092
            	value = values[0];
1093
            	value = EncodingUtilities.decodeString(value);
1094
            }
1095

    
1096
            if (name.equals("fromDate") && value != null) {
1097
                try {
1098
                    startTime = DateTimeMarshaller.deserializeDateToUTC(value);
1099
                } catch (Exception e) {
1100
                    // if we can't parse it, just don't use the startTime param
1101
                    logMetacat.warn("Could not parse fromDate: " + value);
1102
                    startTime = null;
1103
                }
1104
            } else if (name.equals("toDate") && value != null) {
1105
                try {
1106
                    endTime = DateTimeMarshaller.deserializeDateToUTC(value);
1107
                } catch (Exception e) {
1108
                    // if we can't parse it, just don't use the endTime param
1109
                    logMetacat.warn("Could not parse toDate: " + value);
1110
                    endTime = null;
1111
                }
1112
            } else if (name.equals("objectFormat") && value != null) {
1113
            	fmtid = new ObjectFormatIdentifier();
1114
            	fmtid.setValue(value);
1115
            } else if (name.equals("replicaStatus") && value != null) {
1116
                replicaStatus = Boolean.parseBoolean(value);
1117
            } else if (name.equals("start") && value != null) {
1118
                start = Integer.valueOf(value);
1119
            } else if (name.equals("count") && value != null) {
1120
                count = Integer.valueOf(value);
1121
            }
1122
        }
1123
        // make the call
1124
        logMetacat.debug("session: " + session + " fromDate: " + startTime
1125
                + " toDate: " + endTime + " objectFormat: " + fmtid
1126
                + " replicaStatus: " + replicaStatus + " start: " + start
1127
                + " count: " + count);        
1128

    
1129
        // get the list
1130
        ObjectList ol = CNodeService.getInstance(request).listObjects(session,
1131
                startTime, endTime, fmtid, replicaStatus, start, count);
1132

    
1133
        // send it
1134
        OutputStream out = response.getOutputStream();
1135
        response.setStatus(200);
1136
        response.setContentType("text/xml");
1137

    
1138
        // style the object with a processing directive
1139
        String stylesheet = null;
1140
        try {
1141
            stylesheet = PropertyService.getProperty("dataone.types.xsl");
1142
        } catch (PropertyNotFoundException e) {
1143
            logMetacat.warn("Could not locate DataONE types XSLT: "
1144
                    + e.getMessage());
1145
        }
1146

    
1147
        // Serialize and write it to the output stream
1148
        TypeMarshaller.marshalTypeToOutputStream(ol, out, stylesheet);
1149
    }
1150

    
1151
    /**
1152
     * Pass the request to get node replication authorization to CNodeService
1153
     * 
1154
     * @param pid
1155
     *            the identifier of the object to get authorization to replicate
1156
     * 
1157
     * @throws NotImplemented
1158
     * @throws NotAuthorized
1159
     * @throws InvalidToken
1160
     * @throws ServiceFailure
1161
     * @throws NotFound
1162
     * @throws InvalidRequest
1163
     */
1164
    public boolean isNodeAuthorized(String pid) throws NotImplemented,
1165
            NotAuthorized, InvalidToken, ServiceFailure, NotFound,
1166
            InvalidRequest {
1167

    
1168
        boolean result = false;
1169
        Subject targetNodeSubject = new Subject();
1170
        String nodeSubject = null;
1171
        String replPermission = null;
1172

    
1173
        // get the pid
1174
        Identifier identifier = new Identifier();
1175
        identifier.setValue(pid);
1176

    
1177
        // get the target node subject
1178
        try {
1179
            nodeSubject = params.get("targetNodeSubject")[0];
1180
            targetNodeSubject.setValue(nodeSubject);
1181

    
1182
        } catch (NullPointerException e) {
1183
            String msg = "The 'targetNodeSubject' must be provided as a parameter and was not.";
1184
            logMetacat.error(msg);
1185
            throw new InvalidRequest("4873", msg);
1186

    
1187
        }
1188

    
1189
        result = CNodeService.getInstance(request).isNodeAuthorized(session, targetNodeSubject, identifier);
1190

    
1191
        response.setStatus(200);
1192
        response.setContentType("text/xml");
1193
        return result;
1194

    
1195
    }
1196

    
1197
    /**
1198
     * Pass the request to set the replication policy to CNodeService
1199
     * 
1200
     * @param pid
1201
     *            the identifier of the object to set the replication policy on
1202
     * 
1203
     * @throws NotImplemented
1204
     * @throws NotFound
1205
     * @throws NotAuthorized
1206
     * @throws ServiceFailure
1207
     * @throws InvalidRequest
1208
     * @throws InvalidToken
1209
     * @throws IOException
1210
     * @throws InstantiationException
1211
     * @throws IllegalAccessException
1212
     * @throws JiBXException
1213
     * @throws VersionMismatch 
1214
     */
1215
    public boolean setReplicationPolicy(String pid) throws NotImplemented,
1216
            NotFound, NotAuthorized, ServiceFailure, InvalidRequest,
1217
            InvalidToken, IOException, InstantiationException,
1218
            IllegalAccessException, JiBXException, VersionMismatch {
1219

    
1220
        boolean result = false;
1221
        ReplicationPolicy policy = null;
1222
        long serialVersion = 0L;
1223
        String serialVersionStr = null;
1224

    
1225
        Identifier identifier = new Identifier();
1226
        identifier.setValue(pid);
1227

    
1228
        policy = collectReplicationPolicy();
1229

    
1230
        // get the serialVersion
1231
        try {
1232
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1233
            serialVersion = new Long(serialVersionStr).longValue();
1234

    
1235
        } catch (NullPointerException e) {
1236
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1237
            logMetacat.error(msg);
1238
            throw new InvalidRequest("4883", msg);
1239

    
1240
        }
1241
        result = CNodeService.getInstance(request).setReplicationPolicy(
1242
                session, identifier, policy, serialVersion);
1243
        response.setStatus(200);
1244
        response.setContentType("text/xml");
1245
        return result;
1246

    
1247
    }
1248
    
1249
    public boolean setObsoletedBy(String pid) throws NotImplemented,
1250
	    NotFound, NotAuthorized, ServiceFailure, InvalidRequest,
1251
	    InvalidToken, IOException, InstantiationException,
1252
	    IllegalAccessException, JiBXException, VersionMismatch {
1253
	
1254
		boolean result = false;
1255
		long serialVersion = 0L;
1256
		String serialVersionStr = null;
1257
		
1258
		Identifier identifier = new Identifier();
1259
		identifier.setValue(pid);
1260
		
1261
		Identifier obsoletedByPid = null;
1262
		try {
1263
			String obsoletedByPidString = params.get("obsoletedByPid")[0];
1264
			obsoletedByPid = new Identifier();
1265
			obsoletedByPid.setValue(obsoletedByPidString);
1266
		} catch (NullPointerException e) {
1267
		    String msg = "The 'obsoletedByPid' must be provided as a parameter and was not.";
1268
		    logMetacat.error(msg);
1269
		    throw new InvalidRequest("4883", msg);
1270
		}
1271
		
1272
		// get the serialVersion
1273
		try {
1274
		    serialVersionStr = params.get("serialVersion")[0];
1275
		    serialVersion = new Long(serialVersionStr).longValue();
1276
		
1277
		} catch (NullPointerException e) {
1278
		    String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1279
		    logMetacat.error(msg);
1280
		    throw new InvalidRequest("4883", msg);
1281
		
1282
		}
1283
		result = CNodeService.getInstance(request).setObsoletedBy(
1284
		        session, identifier, obsoletedByPid, serialVersion);
1285
		response.setStatus(200);
1286
		response.setContentType("text/xml");
1287
		return result;
1288
	
1289
	}
1290
    
1291
    public boolean deleteReplica(String pid) throws NotImplemented, NotFound,
1292
			NotAuthorized, ServiceFailure, InvalidRequest, InvalidToken,
1293
			IOException, InstantiationException, IllegalAccessException,
1294
			JiBXException, VersionMismatch {
1295

    
1296
		boolean result = false;
1297
		long serialVersion = 0L;
1298
		String serialVersionStr = null;
1299

    
1300
		Identifier identifier = new Identifier();
1301
		identifier.setValue(pid);
1302

    
1303
		NodeReference nodeId = null;
1304
		try {
1305
			String nodeIdString = params.get("nodeId")[0];
1306
			nodeId = new NodeReference();
1307
			nodeId.setValue(nodeIdString);
1308
		} catch (NullPointerException e) {
1309
			String msg = "The 'nodeId' must be provided as a parameter and was not.";
1310
			logMetacat.error(msg);
1311
			throw new InvalidRequest("4883", msg);
1312
		}
1313

    
1314
		// get the serialVersion
1315
		try {
1316
			serialVersionStr = params.get("serialVersion")[0];
1317
			serialVersion = new Long(serialVersionStr).longValue();
1318

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

    
1324
		}
1325
		result = CNodeService.getInstance(request).deleteReplicationMetadata(session, identifier, nodeId, serialVersion);
1326
		response.setStatus(200);
1327
		response.setContentType("text/xml");
1328
		return result;
1329

    
1330
	}
1331

    
1332
    /**
1333
     * Pass the request to set the replication status to CNodeService
1334
     * 
1335
     * @param pid
1336
     *            the identifier of the object to set the replication status on
1337
     * 
1338
     * @throws ServiceFailure
1339
     * @throws NotImplemented
1340
     * @throws InvalidToken
1341
     * @throws NotAuthorized
1342
     * @throws InvalidRequest
1343
     * @throws NotFound
1344
     * @throws JiBXException 
1345
     * @throws IllegalAccessException 
1346
     * @throws InstantiationException 
1347
     * @throws IOException 
1348
     */
1349
    public boolean setReplicationStatus(String pid) throws ServiceFailure,
1350
            NotImplemented, InvalidToken, NotAuthorized, InvalidRequest,
1351
            NotFound {
1352
        
1353
        boolean result = false;
1354
        Identifier identifier = new Identifier();
1355
        identifier.setValue(pid);
1356
        BaseException failure = null;
1357
        ReplicationStatus status = null;
1358
        String replicationStatus = null;
1359
        NodeReference targetNodeRef = null;
1360
        String targetNode = null;
1361

    
1362
        // Parse the params out of the multipart form data
1363
        // Read the incoming data from its Mime Multipart encoding
1364
        logMetacat.debug("Parsing ReplicaStatus from the mime multipart entity");
1365

    
1366
        try {
1367
            failure = collectReplicationStatus();
1368
            
1369
        } catch (IOException e2) {
1370
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1371
                e2.getMessage());
1372
            
1373
        } catch (InstantiationException e2) {
1374
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1375
                e2.getMessage());
1376
            
1377
        } catch (IllegalAccessException e2) {
1378
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1379
                    e2.getMessage());
1380
            
1381
        } catch (JiBXException e2) {
1382
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1383
                    e2.getMessage());
1384
            
1385
        }
1386
        
1387
        // get the replication status param
1388
        try {
1389
            replicationStatus = multipartparams.get("status").get(0);
1390
            status = ReplicationStatus.convert(replicationStatus);
1391

    
1392
        } catch (NullPointerException npe) {
1393

    
1394
            logMetacat.debug("The 'status' parameter was not found in the "
1395
                    + "multipartparams map.  Trying the params map.");
1396

    
1397
            try {
1398
                replicationStatus = params.get("status")[0];
1399
                status = ReplicationStatus.convert(replicationStatus
1400
                        .toLowerCase());
1401

    
1402
            } catch (Exception e) {
1403
                String msg = "The 'status' must be provided as a parameter and was not.";
1404
                logMetacat.error(msg);
1405
                throw new InvalidRequest("4730", msg);
1406

    
1407
            }
1408

    
1409
        }
1410

    
1411
        // get the target node reference param
1412
        try {
1413
            targetNode = multipartparams.get("nodeRef").get(0);
1414
            targetNodeRef = new NodeReference();
1415
            targetNodeRef.setValue(targetNode);
1416

    
1417
        } catch (NullPointerException e) {
1418
            logMetacat.debug("The 'nodeRef' parameter was not found in the "
1419
                    + "multipartparams map.  Trying the params map.");
1420

    
1421
            try {
1422
                targetNode = params.get("nodeRef")[0];
1423
                targetNodeRef = new NodeReference();
1424
                targetNodeRef.setValue(targetNode);
1425

    
1426
            } catch (Exception e1) {
1427
                String msg = "The 'nodeRef' must be provided as a parameter and was not.";
1428
                logMetacat.error(msg);
1429
                throw new InvalidRequest("4730", msg);
1430

    
1431
            }
1432

    
1433
        }
1434

    
1435
        result = CNodeService.getInstance(request).setReplicationStatus(
1436
                session, identifier, targetNodeRef, status, failure);
1437
        response.setStatus(200);
1438
        response.setContentType("text/xml");
1439
        return result;
1440

    
1441
    }
1442

    
1443
    /**
1444
     * Pass the request to update the replication metadata to CNodeService
1445
     * 
1446
     * @param pid
1447
     *            the identifier of the object to update the replication
1448
     *            metadata on
1449
     * 
1450
     * @throws ServiceFailure
1451
     * @throws NotImplemented
1452
     * @throws InvalidToken
1453
     * @throws NotAuthorized
1454
     * @throws InvalidRequest
1455
     * @throws NotFound
1456
     * @throws VersionMismatch 
1457
     */
1458
    public boolean updateReplicationMetadata(String pid) throws ServiceFailure,
1459
            NotImplemented, InvalidToken, NotAuthorized, InvalidRequest,
1460
            NotFound, VersionMismatch {
1461

    
1462
        boolean result = false;
1463
        long serialVersion = 0L;
1464
        String serialVersionStr = null;
1465
        Replica replica = null;
1466
        Identifier identifier = new Identifier();
1467
        identifier.setValue(pid);
1468

    
1469
        replica = collectReplicaMetadata();
1470

    
1471
        // get the serialVersion
1472
        try {
1473
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1474
            serialVersion = new Long(serialVersionStr).longValue();
1475

    
1476
        } catch (NullPointerException e) {
1477
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1478
            logMetacat.error(msg);
1479
            throw new InvalidRequest("4853", msg);
1480

    
1481
        }
1482

    
1483
        result = CNodeService.getInstance(request).updateReplicationMetadata(
1484
                session, identifier, replica, serialVersion);
1485
        response.setStatus(200);
1486
        response.setContentType("text/xml");
1487
        return result;
1488

    
1489
    }
1490

    
1491
}
(1-1/9)