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-27 08:53:02 -0700 (Tue, 27 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.File;
26
import java.io.FileInputStream;
27
import java.io.IOException;
28
import java.io.InputStream;
29
import java.io.OutputStream;
30
import java.util.Date;
31
import java.util.Enumeration;
32
import java.util.Map;
33

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

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

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

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

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

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

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

    
143
        try {
144

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

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

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

    
163
            if (resource != null) {
164

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
299
                    }
300

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

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

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

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

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

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

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

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

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

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

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

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

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

    
432
    }
433

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

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

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

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

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

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

    
498
        TypeMarshaller.marshalTypeToOutputStream(log, out);
499

    
500
    }
501

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

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

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

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

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

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

    
563
    }
564

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

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

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

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

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

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

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

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

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

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

    
656
            TypeMarshaller.marshalTypeToOutputStream(rId, out);
657

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

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

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

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

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

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

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

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

    
710
		TypeMarshaller.marshalTypeToOutputStream(result, out);
711

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

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

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

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

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

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

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

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

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

    
810
        TypeMarshaller.marshalTypeToOutputStream(objectFormat, out);
811

    
812
    }
813

    
814
    /**
815
     * Reserve the given Identifier
816
     * 
817
     * @throws InvalidToken
818
     * @throws ServiceFailure
819
     * @throws NotAuthorized
820
     * @throws IdentifierNotUnique
821
     * @throws NotImplemented
822
     * @throws InvalidRequest
823
     */
824
    private void reserve() 
825
        throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique, 
826
        NotImplemented, InvalidRequest {
827
        Identifier pid = null;
828
        String scope = null;
829
        String format = null;
830

    
831
        // Parse the params out of the multipart form data
832
        logMetacat.debug("Parsing reserve parameters from the mime multipart entity");
833
        try {
834
            collectMultipartParams();
835
            
836
        } catch (FileUploadException e1) {
837
            String msg = "FileUploadException: Couldn't parse the mime multipart information: " +
838
            e1.getMessage();
839
            logMetacat.debug(msg);
840
            throw new ServiceFailure("4210", msg);
841

    
842
        } catch (IOException e1) {
843
            String msg = "IOException: Couldn't parse the mime multipart information: " +
844
            e1.getMessage();
845
            logMetacat.debug(msg);
846
            throw new ServiceFailure("4210", msg);
847
        
848
        } catch (Exception e1) {
849
            String msg = "Exception: Couldn't parse the mime multipart information: " +
850
            e1.getMessage();
851
            logMetacat.debug(msg);
852
            throw new ServiceFailure("4210", msg);
853

    
854
        }
855
        
856
        // gather the params
857
        try {
858
            String id = multipartparams.get("pid").get(0);
859
            pid = new Identifier();
860
            pid.setValue(id);
861
            
862
        } catch (NullPointerException e) {
863
            String msg = "The 'pid' must be provided as a parameter and was not.";
864
            logMetacat.error(msg);
865
            throw new InvalidRequest("4200", msg);
866
 
867
        }
868
        
869
        // call the implementation
870
        try {
871
            Identifier resultPid = CNodeService.getInstance(request).reserveIdentifier(session, pid);
872
            OutputStream out = response.getOutputStream();
873
            response.setStatus(200);
874
            response.setContentType("text/xml");
875
            // send back the reserved pid
876
            TypeMarshaller.marshalTypeToOutputStream(resultPid, out);
877
            
878
        } catch (IOException e) {
879
            String msg = "Couldn't write the identifier to the response output stream: " +
880
                e.getMessage();
881
            logMetacat.debug(msg);
882
            throw new ServiceFailure("4210", msg);
883
        
884
        } catch (JiBXException e) {
885
            String msg = "Couldn't marshall the identifier to the response output stream: " +
886
            e.getMessage();
887
            logMetacat.debug(msg);
888
            throw new ServiceFailure("4210", msg);
889
            
890
        }
891
    }
892

    
893
    /**
894
     * 
895
     * @param id
896
     * @throws InvalidRequest
897
     * @throws InvalidToken
898
     * @throws ServiceFailure
899
     * @throws NotAuthorized
900
     * @throws NotFound
901
     * @throws NotImplemented
902
     * @throws IOException
903
     * @throws JiBXException
904
     */
905
    private void resolve(String id) throws InvalidRequest, InvalidToken,
906
            ServiceFailure, NotAuthorized, NotFound, NotImplemented,
907
            IOException, JiBXException {
908
        Identifier pid = new Identifier();
909
        pid.setValue(id);
910
        ObjectLocationList locationList = CNodeService.getInstance(request)
911
                .resolve(session, pid);
912
        OutputStream out = response.getOutputStream();
913
        response.setStatus(200);
914
        response.setContentType("text/xml");
915
        TypeMarshaller.marshalTypeToOutputStream(locationList, out);
916

    
917
    }
918

    
919
    /**
920
     * Set the owner of a resource
921
     * 
922
     * @param id
923
     * @throws InvalidToken
924
     * @throws ServiceFailure
925
     * @throws NotFound
926
     * @throws NotAuthorized
927
     * @throws NotImplemented
928
     * @throws InvalidRequest
929
     * @throws IllegalAccessException
930
     * @throws InstantiationException
931
     * @throws VersionMismatch 
932
     */
933
    private void owner(String id) 
934
        throws InvalidToken, ServiceFailure, NotFound, NotAuthorized, 
935
        NotImplemented, InvalidRequest, InstantiationException, 
936
        IllegalAccessException, VersionMismatch {
937

    
938
        Identifier pid = new Identifier();
939
        pid.setValue(id);
940

    
941
        long serialVersion = 0L;
942
        String serialVersionStr = null;
943
        String userIdStr = null;
944
        Subject userId = null;
945
        
946
        // Parse the params out of the multipart form data
947
        // Read the incoming data from its Mime Multipart encoding
948
        logMetacat.debug("Parsing rights holder parameters from the mime multipart entity");
949
        try {
950
            collectMultipartParams();
951
            
952
        } catch (FileUploadException e1) {
953
            String msg = "FileUploadException: Couldn't parse the mime multipart information: " +
954
            e1.getMessage();
955
            logMetacat.debug(msg);
956
            throw new ServiceFailure("4490", msg);
957

    
958
        } catch (IOException e1) {
959
            String msg = "IOException: Couldn't parse the mime multipart information: " +
960
            e1.getMessage();
961
            logMetacat.debug(msg);
962
            throw new ServiceFailure("4490", msg);
963
        
964
        } catch (Exception e1) {
965
            String msg = "Exception: Couldn't parse the mime multipart information: " +
966
            e1.getMessage();
967
            logMetacat.debug(msg);
968
            throw new ServiceFailure("4490", msg);
969

    
970
        }
971
        
972
        // get the serialVersion
973
        try {
974
            serialVersionStr = multipartparams.get("serialVersion").get(0);
975
            serialVersion = new Long(serialVersionStr).longValue();
976
            
977
        } catch (NumberFormatException nfe) {
978
            String msg = "The 'serialVersion' must be provided as a positive integer and was not.";
979
            logMetacat.error(msg);
980
            throw new InvalidRequest("4442", msg);
981
                        
982
        } catch (NullPointerException e) {
983
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
984
            logMetacat.error(msg);
985
            throw new InvalidRequest("4442", msg);
986
            
987
        }
988

    
989
        // get the subject userId that will become the rights holder
990
        try {
991
            userIdStr = multipartparams.get("userId").get(0);
992
            userId = new Subject();
993
            userId.setValue(userIdStr);
994
                                    
995
        } catch (NullPointerException e) {
996
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
997
            logMetacat.error(msg);
998
            throw new InvalidRequest("4442", msg);
999
            
1000
        }
1001

    
1002
        // set the rights holder
1003
        Identifier retPid = CNodeService.getInstance(request).setRightsHolder(session, pid, userId, serialVersion);
1004
        
1005
        try {
1006
            OutputStream out = response.getOutputStream();
1007
            response.setStatus(200);
1008
            response.setContentType("text/xml");
1009
            TypeMarshaller.marshalTypeToOutputStream(retPid, out);
1010
            
1011
        } catch (IOException e) {
1012
            String msg = "Couldn't write the identifier to the response output stream: " +
1013
                e.getMessage();
1014
            logMetacat.debug(msg);
1015
            throw new ServiceFailure("4490", msg);
1016
        
1017
        } catch (JiBXException e) {
1018
            String msg = "Couldn't marshall the identifier to the response output stream: " +
1019
            e.getMessage();
1020
            logMetacat.debug(msg);
1021
            throw new ServiceFailure("4490", msg);
1022
            
1023
        }
1024
    }
1025

    
1026
    /**
1027
     * Processes the authorization check for given id
1028
     * 
1029
     * @param id
1030
     * @return
1031
     * @throws ServiceFailure
1032
     * @throws InvalidToken
1033
     * @throws NotFound
1034
     * @throws NotAuthorized
1035
     * @throws NotImplemented
1036
     * @throws InvalidRequest
1037
     */
1038
    private boolean isAuthorized(String id) throws ServiceFailure,
1039
            InvalidToken, NotFound, NotAuthorized, NotImplemented,
1040
            InvalidRequest {
1041
        Identifier pid = new Identifier();
1042
        pid.setValue(id);
1043
        String permission = params.get("action")[0];
1044
        boolean result = CNodeService.getInstance(request).isAuthorized(
1045
                session, pid, Permission.convert(permission));
1046
        response.setStatus(200);
1047
        response.setContentType("text/xml");
1048
        return result;
1049
    }
1050

    
1051
    /**
1052
     * Register System Metadata without data or metadata object
1053
     * 
1054
     * @param pid
1055
     *            identifier for System Metadata entry
1056
     * @throws JiBXException
1057
     * @throws FileUploadException
1058
     * @throws IOException
1059
     * @throws InvalidRequest
1060
     * @throws ServiceFailure
1061
     * @throws InvalidSystemMetadata
1062
     * @throws NotAuthorized
1063
     * @throws NotImplemented
1064
     * @throws IllegalAccessException
1065
     * @throws InstantiationException
1066
     */
1067
    protected void registerSystemMetadata()
1068
            throws ServiceFailure, InvalidRequest, IOException,
1069
            FileUploadException, JiBXException, NotImplemented, NotAuthorized,
1070
            InvalidSystemMetadata, InstantiationException,
1071
            IllegalAccessException {
1072
    	
1073
    	// Read the incoming data from its Mime Multipart encoding
1074
        Map<String, File> files = collectMultipartFiles();
1075
        
1076
    	// get the encoded pid string from the body and make the object
1077
        String pidString = multipartparams.get("pid").get(0);
1078
        Identifier pid = new Identifier();
1079
        pid.setValue(pidString);
1080
        
1081
        logMetacat.debug("registerSystemMetadata: " + pid);
1082

    
1083
        // get the system metadata from the request
1084
        File smFile = files.get("sysmeta");
1085
        FileInputStream sysmeta = new FileInputStream(smFile);
1086
        SystemMetadata systemMetadata = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysmeta);
1087

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

    
1091
        OutputStream out = response.getOutputStream();
1092
        response.setStatus(200);
1093
        response.setContentType("text/xml");
1094
        
1095
        TypeMarshaller.marshalTypeToOutputStream(retGuid, out);
1096

    
1097
    }
1098

    
1099
    /**
1100
     * set the access perms on a document
1101
     * 
1102
     * @throws JiBXException
1103
     * @throws InvalidRequest
1104
     * @throws NotImplemented
1105
     * @throws NotAuthorized
1106
     * @throws NotFound
1107
     * @throws ServiceFailure
1108
     * @throws InvalidToken
1109
     * @throws IllegalAccessException
1110
     * @throws InstantiationException
1111
     * @throws IOException
1112
     * @throws SAXException
1113
     * @throws ParserConfigurationException
1114
     * @throws VersionMismatch 
1115
     */
1116
    protected void setAccess(String pid) throws JiBXException, InvalidToken,
1117
            ServiceFailure, NotFound, NotAuthorized, NotImplemented,
1118
            InvalidRequest, IOException, InstantiationException,
1119
            IllegalAccessException, ParserConfigurationException, SAXException, VersionMismatch {
1120

    
1121
        long serialVersion = 0L;
1122
        String serialVersionStr = null;
1123
        AccessPolicy accessPolicy = collectAccessPolicy();
1124

    
1125
        // get the serialVersion
1126
        try {
1127
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1128
            serialVersion = new Long(serialVersionStr).longValue();
1129

    
1130
        } catch (NumberFormatException nfe) {
1131
            String msg = "The 'serialVersion' must be provided as a positive integer and was not.";
1132
            logMetacat.error(msg);
1133
            throw new InvalidRequest("4402", msg);
1134
            
1135
        } catch (NullPointerException e) {
1136
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1137
            logMetacat.error(msg);
1138
            throw new InvalidRequest("4402", msg);
1139

    
1140
        }
1141

    
1142
        Identifier id = new Identifier();
1143
        id.setValue(pid);
1144

    
1145
        CNodeService.getInstance(request).setAccessPolicy(session, id,
1146
                accessPolicy, serialVersion);
1147

    
1148
    }
1149

    
1150
    /**
1151
     * List the objects
1152
     * 
1153
     * @throws NotImplemented
1154
     * @throws InvalidRequest
1155
     * @throws NotAuthorized
1156
     * @throws ServiceFailure
1157
     * @throws InvalidToken
1158
     * @throws NotFound
1159
     * @throws IOException
1160
     * @throws JiBXException
1161
     * @throws Exception
1162
     */
1163
    private void listObjects() throws InvalidToken, ServiceFailure,
1164
            NotAuthorized, InvalidRequest, NotImplemented, NotFound,
1165
            IOException, JiBXException {
1166

    
1167
        Date startTime = null;
1168
        Date endTime = null;
1169
        ObjectFormatIdentifier fmtid = null;
1170
        boolean replicaStatus = false;
1171
        int start = 0;
1172
        int count = -1;
1173
        Enumeration<String> paramlist = request.getParameterNames();
1174
        while (paramlist.hasMoreElements()) {
1175
            // parse the params and make the call
1176
            String name = paramlist.nextElement();
1177
            String[] values = request.getParameterValues(name);
1178
            String value = null;
1179
            if (values != null && values.length > 0) {
1180
            	value = values[0];
1181
            	value = EncodingUtilities.decodeString(value);
1182
            }
1183

    
1184
            if (name.equals("fromDate") && value != null) {
1185
                try {
1186
                    startTime = DateTimeMarshaller.deserializeDateToUTC(value);
1187
                } catch (Exception e) {
1188
                    // if we can't parse it, just don't use the startTime param
1189
                    logMetacat.warn("Could not parse fromDate: " + value);
1190
                    startTime = null;
1191
                }
1192
            } else if (name.equals("toDate") && value != null) {
1193
                try {
1194
                    endTime = DateTimeMarshaller.deserializeDateToUTC(value);
1195
                } catch (Exception e) {
1196
                    // if we can't parse it, just don't use the endTime param
1197
                    logMetacat.warn("Could not parse toDate: " + value);
1198
                    endTime = null;
1199
                }
1200
            } else if (name.equals("objectFormat") && value != null) {
1201
            	fmtid = new ObjectFormatIdentifier();
1202
            	fmtid.setValue(value);
1203
            } else if (name.equals("replicaStatus") && value != null) {
1204
                replicaStatus = Boolean.parseBoolean(value);
1205
            } else if (name.equals("start") && value != null) {
1206
                start = Integer.valueOf(value);
1207
            } else if (name.equals("count") && value != null) {
1208
                count = Integer.valueOf(value);
1209
            }
1210
        }
1211
        // make the call
1212
        logMetacat.debug("session: " + session + " fromDate: " + startTime
1213
                + " toDate: " + endTime + " objectFormat: " + fmtid
1214
                + " replicaStatus: " + replicaStatus + " start: " + start
1215
                + " count: " + count);        
1216

    
1217
        // get the list
1218
        ObjectList ol = CNodeService.getInstance(request).listObjects(session,
1219
                startTime, endTime, fmtid, replicaStatus, start, count);
1220

    
1221
        // send it
1222
        OutputStream out = response.getOutputStream();
1223
        response.setStatus(200);
1224
        response.setContentType("text/xml");
1225

    
1226
        // style the object with a processing directive
1227
        String stylesheet = null;
1228
        try {
1229
            stylesheet = PropertyService.getProperty("dataone.types.xsl");
1230
        } catch (PropertyNotFoundException e) {
1231
            logMetacat.warn("Could not locate DataONE types XSLT: "
1232
                    + e.getMessage());
1233
        }
1234

    
1235
        // Serialize and write it to the output stream
1236
        TypeMarshaller.marshalTypeToOutputStream(ol, out, stylesheet);
1237
    }
1238

    
1239
    /**
1240
     * Pass the request to get node replication authorization to CNodeService
1241
     * 
1242
     * @param pid
1243
     *            the identifier of the object to get authorization to replicate
1244
     * 
1245
     * @throws NotImplemented
1246
     * @throws NotAuthorized
1247
     * @throws InvalidToken
1248
     * @throws ServiceFailure
1249
     * @throws NotFound
1250
     * @throws InvalidRequest
1251
     */
1252
    public boolean isNodeAuthorized(String pid) throws NotImplemented,
1253
            NotAuthorized, InvalidToken, ServiceFailure, NotFound,
1254
            InvalidRequest {
1255

    
1256
        boolean result = false;
1257
        Subject targetNodeSubject = new Subject();
1258
        String nodeSubject = null;
1259
        String replPermission = null;
1260

    
1261
        // get the pid
1262
        Identifier identifier = new Identifier();
1263
        identifier.setValue(pid);
1264

    
1265
        // get the target node subject
1266
        try {
1267
            nodeSubject = params.get("targetNodeSubject")[0];
1268
            targetNodeSubject.setValue(nodeSubject);
1269

    
1270
        } catch (NullPointerException e) {
1271
            String msg = "The 'targetNodeSubject' must be provided as a parameter and was not.";
1272
            logMetacat.error(msg);
1273
            throw new InvalidRequest("4873", msg);
1274

    
1275
        }
1276

    
1277
        result = CNodeService.getInstance(request).isNodeAuthorized(session, targetNodeSubject, identifier);
1278

    
1279
        response.setStatus(200);
1280
        response.setContentType("text/xml");
1281
        return result;
1282

    
1283
    }
1284

    
1285
    /**
1286
     * Pass the request to set the replication policy to CNodeService
1287
     * 
1288
     * @param pid
1289
     *            the identifier of the object to set the replication policy on
1290
     * 
1291
     * @throws NotImplemented
1292
     * @throws NotFound
1293
     * @throws NotAuthorized
1294
     * @throws ServiceFailure
1295
     * @throws InvalidRequest
1296
     * @throws InvalidToken
1297
     * @throws IOException
1298
     * @throws InstantiationException
1299
     * @throws IllegalAccessException
1300
     * @throws JiBXException
1301
     * @throws VersionMismatch 
1302
     */
1303
    public boolean setReplicationPolicy(String pid) throws NotImplemented,
1304
            NotFound, NotAuthorized, ServiceFailure, InvalidRequest,
1305
            InvalidToken, IOException, InstantiationException,
1306
            IllegalAccessException, JiBXException, VersionMismatch {
1307

    
1308
        boolean result = false;
1309
        ReplicationPolicy policy = null;
1310
        long serialVersion = 0L;
1311
        String serialVersionStr = null;
1312

    
1313
        Identifier identifier = new Identifier();
1314
        identifier.setValue(pid);
1315

    
1316
        policy = collectReplicationPolicy();
1317

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

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

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

    
1335
    }
1336
    
1337
    public boolean setObsoletedBy(String pid) throws NotImplemented,
1338
	    NotFound, NotAuthorized, ServiceFailure, InvalidRequest,
1339
	    InvalidToken, IOException, InstantiationException,
1340
	    IllegalAccessException, JiBXException, VersionMismatch {
1341
	
1342
		boolean result = false;
1343
		long serialVersion = 0L;
1344
		String serialVersionStr = null;
1345
		
1346
		Identifier identifier = new Identifier();
1347
		identifier.setValue(pid);
1348
		
1349
		Identifier obsoletedByPid = null;
1350
		try {
1351
			String obsoletedByPidString = params.get("obsoletedByPid")[0];
1352
			obsoletedByPid = new Identifier();
1353
			obsoletedByPid.setValue(obsoletedByPidString);
1354
		} catch (NullPointerException e) {
1355
		    String msg = "The 'obsoletedByPid' must be provided as a parameter and was not.";
1356
		    logMetacat.error(msg);
1357
		    throw new InvalidRequest("4883", msg);
1358
		}
1359
		
1360
		// get the serialVersion
1361
		try {
1362
		    serialVersionStr = params.get("serialVersion")[0];
1363
		    serialVersion = new Long(serialVersionStr).longValue();
1364
		
1365
		} catch (NullPointerException e) {
1366
		    String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1367
		    logMetacat.error(msg);
1368
		    throw new InvalidRequest("4883", msg);
1369
		
1370
		}
1371
		result = CNodeService.getInstance(request).setObsoletedBy(
1372
		        session, identifier, obsoletedByPid, serialVersion);
1373
		response.setStatus(200);
1374
		response.setContentType("text/xml");
1375
		return result;
1376
	
1377
	}
1378
    
1379
    public boolean deleteReplica(String pid) throws NotImplemented, NotFound,
1380
			NotAuthorized, ServiceFailure, InvalidRequest, InvalidToken,
1381
			IOException, InstantiationException, IllegalAccessException,
1382
			JiBXException, VersionMismatch {
1383

    
1384
		boolean result = false;
1385
		long serialVersion = 0L;
1386
		String serialVersionStr = null;
1387

    
1388
		Identifier identifier = new Identifier();
1389
		identifier.setValue(pid);
1390

    
1391
		NodeReference nodeId = null;
1392
		try {
1393
			String nodeIdString = params.get("nodeId")[0];
1394
			nodeId = new NodeReference();
1395
			nodeId.setValue(nodeIdString);
1396
		} catch (NullPointerException e) {
1397
			String msg = "The 'nodeId' must be provided as a parameter and was not.";
1398
			logMetacat.error(msg);
1399
			throw new InvalidRequest("4883", msg);
1400
		}
1401

    
1402
		// get the serialVersion
1403
		try {
1404
			serialVersionStr = params.get("serialVersion")[0];
1405
			serialVersion = new Long(serialVersionStr).longValue();
1406

    
1407
		} catch (NullPointerException e) {
1408
			String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1409
			logMetacat.error(msg);
1410
			throw new InvalidRequest("4883", msg);
1411

    
1412
		}
1413
		result = CNodeService.getInstance(request).deleteReplicationMetadata(session, identifier, nodeId, serialVersion);
1414
		response.setStatus(200);
1415
		response.setContentType("text/xml");
1416
		return result;
1417

    
1418
	}
1419

    
1420
    /**
1421
     * Pass the request to set the replication status to CNodeService
1422
     * 
1423
     * @param pid
1424
     *            the identifier of the object to set the replication status on
1425
     * 
1426
     * @throws ServiceFailure
1427
     * @throws NotImplemented
1428
     * @throws InvalidToken
1429
     * @throws NotAuthorized
1430
     * @throws InvalidRequest
1431
     * @throws NotFound
1432
     * @throws JiBXException 
1433
     * @throws IllegalAccessException 
1434
     * @throws InstantiationException 
1435
     * @throws IOException 
1436
     */
1437
    public boolean setReplicationStatus(String pid) throws ServiceFailure,
1438
            NotImplemented, InvalidToken, NotAuthorized, InvalidRequest,
1439
            NotFound {
1440
        
1441
        boolean result = false;
1442
        Identifier identifier = new Identifier();
1443
        identifier.setValue(pid);
1444
        BaseException failure = null;
1445
        ReplicationStatus status = null;
1446
        String replicationStatus = null;
1447
        NodeReference targetNodeRef = null;
1448
        String targetNode = null;
1449

    
1450
        // Parse the params out of the multipart form data
1451
        // Read the incoming data from its Mime Multipart encoding
1452
        logMetacat.debug("Parsing ReplicaStatus from the mime multipart entity");
1453

    
1454
        try {
1455
            failure = collectReplicationStatus();
1456
            
1457
        } catch (IOException e2) {
1458
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1459
                e2.getMessage());
1460
            
1461
        } catch (InstantiationException e2) {
1462
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1463
                e2.getMessage());
1464
            
1465
        } catch (IllegalAccessException e2) {
1466
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1467
                    e2.getMessage());
1468
            
1469
        } catch (JiBXException e2) {
1470
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1471
                    e2.getMessage());
1472
            
1473
        }
1474
        
1475
        // get the replication status param
1476
        try {
1477
            replicationStatus = multipartparams.get("status").get(0);
1478
            status = ReplicationStatus.convert(replicationStatus);
1479

    
1480
        } catch (NullPointerException npe) {
1481

    
1482
            logMetacat.debug("The 'status' parameter was not found in the "
1483
                    + "multipartparams map.  Trying the params map.");
1484

    
1485
            try {
1486
                replicationStatus = params.get("status")[0];
1487
                status = ReplicationStatus.convert(replicationStatus
1488
                        .toLowerCase());
1489

    
1490
            } catch (Exception e) {
1491
                String msg = "The 'status' must be provided as a parameter and was not.";
1492
                logMetacat.error(msg);
1493
                throw new InvalidRequest("4730", msg);
1494

    
1495
            }
1496

    
1497
        }
1498

    
1499
        // get the target node reference param
1500
        try {
1501
            targetNode = multipartparams.get("nodeRef").get(0);
1502
            targetNodeRef = new NodeReference();
1503
            targetNodeRef.setValue(targetNode);
1504

    
1505
        } catch (NullPointerException e) {
1506
            logMetacat.debug("The 'nodeRef' parameter was not found in the "
1507
                    + "multipartparams map.  Trying the params map.");
1508

    
1509
            try {
1510
                targetNode = params.get("nodeRef")[0];
1511
                targetNodeRef = new NodeReference();
1512
                targetNodeRef.setValue(targetNode);
1513

    
1514
            } catch (Exception e1) {
1515
                String msg = "The 'nodeRef' must be provided as a parameter and was not.";
1516
                logMetacat.error(msg);
1517
                throw new InvalidRequest("4730", msg);
1518

    
1519
            }
1520

    
1521
        }
1522

    
1523
        result = CNodeService.getInstance(request).setReplicationStatus(
1524
                session, identifier, targetNodeRef, status, failure);
1525
        response.setStatus(200);
1526
        response.setContentType("text/xml");
1527
        return result;
1528

    
1529
    }
1530

    
1531
    /**
1532
     * Pass the request to update the replication metadata to CNodeService
1533
     * 
1534
     * @param pid
1535
     *            the identifier of the object to update the replication
1536
     *            metadata on
1537
     * 
1538
     * @throws ServiceFailure
1539
     * @throws NotImplemented
1540
     * @throws InvalidToken
1541
     * @throws NotAuthorized
1542
     * @throws InvalidRequest
1543
     * @throws NotFound
1544
     * @throws VersionMismatch 
1545
     */
1546
    public boolean updateReplicationMetadata(String pid) throws ServiceFailure,
1547
            NotImplemented, InvalidToken, NotAuthorized, InvalidRequest,
1548
            NotFound, VersionMismatch {
1549

    
1550
        boolean result = false;
1551
        long serialVersion = 0L;
1552
        String serialVersionStr = null;
1553
        Replica replica = null;
1554
        Identifier identifier = new Identifier();
1555
        identifier.setValue(pid);
1556

    
1557
        replica = collectReplicaMetadata();
1558

    
1559
        // get the serialVersion
1560
        try {
1561
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1562
            serialVersion = new Long(serialVersionStr).longValue();
1563

    
1564
        } catch (NullPointerException e) {
1565
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1566
            logMetacat.error(msg);
1567
            throw new InvalidRequest("4853", msg);
1568

    
1569
        }
1570

    
1571
        result = CNodeService.getInstance(request).updateReplicationMetadata(
1572
                session, identifier, replica, serialVersion);
1573
        response.setStatus(200);
1574
        response.setContentType("text/xml");
1575
        return result;
1576

    
1577
    }
1578

    
1579
}
(1-1/9)