Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *  Copyright: 2011 Regents of the University of California and the
4
 *              National Center for Ecological Analysis and Synthesis
5
 *
6
 *   '$Author: leinfelder $'
7
 *     '$Date: 2014-07-23 16:19:48 -0700 (Wed, 23 Jul 2014) $'
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.v1;
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.v2.formats.ObjectFormatInfo;
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.ExceptionHandler;
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.v1.CNodeService;
83
import edu.ucsb.nceas.metacat.properties.PropertyService;
84
import edu.ucsb.nceas.metacat.restservice.D1ResourceHandler;
85
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
86

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

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

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

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

    
145
        try {
146

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

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

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

    
165
            if (resource != null) {
166

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
284
                } else if (resource.startsWith(Constants.RESOURCE_ARCHIVE)) {
285
                    logMetacat.debug("Using resource " + Constants.RESOURCE_ARCHIVE);
286
                    // handle archive events
287
                    if (httpVerb == PUT) {
288
                        extra = parseTrailing(resource, Constants.RESOURCE_ARCHIVE);
289
                        archive(extra);
290
                        status = true;
291
                    }
292
                } else if (resource.startsWith(Constants.RESOURCE_CHECKSUM)) {
293
                    logMetacat.debug("Using resource: " + Constants.RESOURCE_CHECKSUM);
294

    
295
                    // after the command
296
                    extra = parseTrailing(resource, Constants.RESOURCE_CHECKSUM);
297

    
298
                    // handle checksum requests
299
                    if (httpVerb == GET) {
300

    
301
                    	if (extra != null && extra.length() > 0) {
302
	                        checksum(extra);
303
	                        status = true;
304
                    	} else {
305
                    		listChecksumAlgorithms();
306
                    		status = true;
307
                    	}
308

    
309
                    }
310

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

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

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

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

    
331
                } else if (resource.startsWith(RESOURCE_REPLICATION_NOTIFY)
332
                        && httpVerb == PUT) {
333

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

    
341
                } else if (resource.startsWith(RESOURCE_REPLICATION_AUTHORIZED)
342
                        && httpVerb == GET) {
343

    
344
                    logMetacat.debug("Using resource: "
345
                            + RESOURCE_REPLICATION_AUTHORIZED);
346
                    // get the trailing pid
347
                    extra = parseTrailing(resource,
348
                            RESOURCE_REPLICATION_AUTHORIZED);
349
                    isNodeAuthorized(extra);
350
                    status = true;
351

    
352
                } else if (resource.startsWith(Constants.RESOURCE_MONITOR_PING)) {
353
                    if (httpVerb == GET) {
354
                    	// after the command
355
                        extra = parseTrailing(resource, Constants.RESOURCE_MONITOR_PING);
356
                        
357
                        logMetacat.debug("processing ping request");
358
                        Date result = CNodeService.getInstance(request).ping();
359
                        // TODO: send to output	
360
                        status = true;
361
                    }
362
                } else if (resource.startsWith(Constants.RESOURCE_META_OBSOLETEDBY)
363
                        && httpVerb == PUT) {
364

    
365
                    logMetacat.debug("Using resource: "
366
                            + Constants.RESOURCE_META_OBSOLETEDBY);
367
                    // get the trailing pid
368
                    extra = parseTrailing(resource, Constants.RESOURCE_META_OBSOLETEDBY);
369
                    setObsoletedBy(extra);
370
                    status = true;
371
                } else if (resource.startsWith(Constants.RESOURCE_REPLICATION_DELETE_REPLICA)
372
                        && httpVerb == PUT) {
373

    
374
                    logMetacat.debug("Using resource: "
375
                            + Constants.RESOURCE_REPLICATION_DELETE_REPLICA);
376
                    // get the trailing pid
377
                    extra = parseTrailing(resource, Constants.RESOURCE_REPLICATION_DELETE_REPLICA);
378
                    deleteReplica(extra);
379
                    status = true;
380
                }
381

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

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

    
442
    }
443

    
444
    /**
445
     * get the logs based on passed params. Available params are token,
446
     * fromDate, toDate, event. See
447
     * http://mule1.dataone.org/ArchitectureDocs/mn_api_crud
448
     * .html#MN_crud.getLogRecords for more info
449
     * 
450
     * @throws NotImplemented
451
     * @throws InvalidRequest
452
     * @throws NotAuthorized
453
     * @throws ServiceFailure
454
     * @throws InvalidToken
455
     * @throws IOException
456
     * @throws JiBXException
457
     * @throws InsufficientResources 
458
     */
459
    private void getLog() throws InvalidToken, ServiceFailure, NotAuthorized,
460
            InvalidRequest, NotImplemented, IOException, JiBXException, InsufficientResources {
461

    
462
        Date fromDate = null;
463
        Date toDate = null;
464
        Event event = null;
465
        Integer start = null;
466
        Integer count = null;
467
        String pidFilter = null;
468

    
469
        try {
470
            String fromDateS = params.get("fromDate")[0];
471
            logMetacat.debug("param fromDateS: " + fromDateS);
472
            fromDate = DateTimeMarshaller.deserializeDateToUTC(fromDateS);
473
        } catch (Exception e) {
474
            logMetacat.warn("Could not parse fromDate: " + e.getMessage());
475
        }
476
        try {
477
            String toDateS = params.get("toDate")[0];
478
            logMetacat.debug("param toDateS: " + toDateS);
479
            toDate = DateTimeMarshaller.deserializeDateToUTC(toDateS);
480
        } catch (Exception e) {
481
            logMetacat.warn("Could not parse toDate: " + e.getMessage());
482
        }
483
        try {
484
            String eventS = params.get("event")[0];
485
            event = Event.convert(eventS);
486
        } catch (Exception e) {
487
            logMetacat.warn("Could not parse event: " + e.getMessage());
488
        }
489
        logMetacat.debug("fromDate: " + fromDate + " toDate: " + toDate);
490

    
491
        try {
492
            start = Integer.parseInt(params.get("start")[0]);
493
        } catch (Exception e) {
494
            logMetacat.warn("Could not parse start: " + e.getMessage());
495
        }
496
        try {
497
            count = Integer.parseInt(params.get("count")[0]);
498
        } catch (Exception e) {
499
            logMetacat.warn("Could not parse count: " + e.getMessage());
500
        }
501

    
502
        try {
503
            pidFilter = params.get("pidFilter")[0];
504
        } catch (Exception e) {
505
            logMetacat.warn("Could not parse pidFilter: " + e.getMessage());
506
        }
507
        
508
        logMetacat.debug("calling getLogRecords");
509
        Log log = CNodeService.getInstance(request).getLogRecords(session,
510
                fromDate, toDate, event, pidFilter, start, count);
511

    
512
        OutputStream out = response.getOutputStream();
513
        response.setStatus(200);
514
        response.setContentType("text/xml");
515

    
516
        TypeMarshaller.marshalTypeToOutputStream(log, out);
517

    
518
    }
519

    
520
    /**
521
     * Implements REST version of DataONE CRUD API --> get
522
     * 
523
     * @param guid
524
     *            ID of data object to be read
525
     * @throws NotImplemented
526
     * @throws InvalidRequest
527
     * @throws NotFound
528
     * @throws NotAuthorized
529
     * @throws ServiceFailure
530
     * @throws InvalidToken
531
     * @throws IOException
532
     */
533
    protected void getObject(String guid) throws InvalidToken, ServiceFailure,
534
            NotAuthorized, NotFound, InvalidRequest, NotImplemented,
535
            IOException {
536

    
537
        Identifier id = new Identifier();
538
        id.setValue(guid);
539

    
540
        SystemMetadata sm = CNodeService.getInstance(request)
541
                .getSystemMetadata(session, id);
542

    
543
        // set the headers for the content
544
        String mimeType = ObjectFormatInfo.instance().getMimeType(sm.getFormatId().getValue());
545
        if (mimeType == null) {
546
        	mimeType = "application/octet-stream";
547
        }
548
        String extension = ObjectFormatInfo.instance().getExtension(sm.getFormatId().getValue());
549
        String filename = id.getValue();
550
        if (extension != null) {
551
        	filename = id.getValue() + extension;
552
        }
553
        response.setContentType(mimeType);
554
        response.setHeader("Content-Disposition", "inline; filename=" + filename);
555

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

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

    
562
    }
563

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

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

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

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

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

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

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

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

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

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

    
655
            TypeMarshaller.marshalTypeToOutputStream(rId, out);
656

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

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

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

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

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

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

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

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

    
709
		TypeMarshaller.marshalTypeToOutputStream(result, out);
710

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

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

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

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

    
774
        logMetacat.debug("Calling delete for identifier " + pid);
775
        CNodeService.getInstance(request).delete(session, id);
776
        TypeMarshaller.marshalTypeToOutputStream(id, out);
777
        
778
    }
779
    
780
    /**
781
     * Archives the given pid
782
     * @param pid
783
     * @throws InvalidToken
784
     * @throws ServiceFailure
785
     * @throws NotAuthorized
786
     * @throws NotFound
787
     * @throws NotImplemented
788
     * @throws IOException
789
     * @throws JiBXException
790
     * @throws InvalidRequest 
791
     */
792
    private void archive(String pid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, IOException, JiBXException, InvalidRequest {
793

    
794
        OutputStream out = response.getOutputStream();
795
        response.setStatus(200);
796
        response.setContentType("text/xml");
797

    
798
        Identifier id = new Identifier();
799
        id.setValue(pid);
800

    
801
        logMetacat.debug("Calling archive");
802
        CNodeService.getInstance(request).archive(session, id);
803
        
804
        TypeMarshaller.marshalTypeToOutputStream(id, out);
805
        
806
    }
807

    
808
    /**
809
     * Return the requested object format
810
     * 
811
     * @param fmtidStr
812
     *            the requested format identifier as a string
813
     * @throws NotImplemented
814
     * @throws InsufficientResources
815
     * @throws NotFound
816
     * @throws ServiceFailure
817
     * @throws InvalidRequest
818
     * @throws IOException
819
     * @throws JiBXException
820
     */
821
    private void getFormat(String fmtidStr) throws InvalidRequest,
822
            ServiceFailure, NotFound, InsufficientResources, NotImplemented,
823
            IOException, JiBXException {
824
        logMetacat.debug("Entering listFormats()");
825

    
826
        ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
827
        fmtid.setValue(fmtidStr);
828

    
829
        // get the specified object format
830
        ObjectFormat objectFormat = CNodeService.getInstance(request)
831
                .getFormat(fmtid);
832

    
833
        OutputStream out = response.getOutputStream();
834
        response.setStatus(200);
835
        response.setContentType("text/xml");
836

    
837
        TypeMarshaller.marshalTypeToOutputStream(objectFormat, out);
838

    
839
    }
840

    
841
    /**
842
     * Reserve the given Identifier
843
     * 
844
     * @throws InvalidToken
845
     * @throws ServiceFailure
846
     * @throws NotAuthorized
847
     * @throws IdentifierNotUnique
848
     * @throws NotImplemented
849
     * @throws InvalidRequest
850
     */
851
    private void reserve() 
852
        throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique, 
853
        NotImplemented, InvalidRequest {
854
        Identifier pid = null;
855
        String scope = null;
856
        String format = null;
857

    
858
        // Parse the params out of the multipart form data
859
        logMetacat.debug("Parsing reserve parameters from the mime multipart entity");
860
        try {
861
            collectMultipartParams();
862
            
863
        } catch (FileUploadException e1) {
864
            String msg = "FileUploadException: Couldn't parse the mime multipart information: " +
865
            e1.getMessage();
866
            logMetacat.debug(msg);
867
            throw new ServiceFailure("4210", msg);
868

    
869
        } catch (IOException e1) {
870
            String msg = "IOException: Couldn't parse the mime multipart information: " +
871
            e1.getMessage();
872
            logMetacat.debug(msg);
873
            throw new ServiceFailure("4210", msg);
874
        
875
        } catch (Exception e1) {
876
            String msg = "Exception: Couldn't parse the mime multipart information: " +
877
            e1.getMessage();
878
            logMetacat.debug(msg);
879
            throw new ServiceFailure("4210", msg);
880

    
881
        }
882
        
883
        // gather the params
884
        try {
885
            String id = multipartparams.get("pid").get(0);
886
            pid = new Identifier();
887
            pid.setValue(id);
888
            
889
        } catch (NullPointerException e) {
890
            String msg = "The 'pid' must be provided as a parameter and was not.";
891
            logMetacat.error(msg);
892
            throw new InvalidRequest("4200", msg);
893
 
894
        }
895
        
896
        // call the implementation
897
        try {
898
            Identifier resultPid = CNodeService.getInstance(request).reserveIdentifier(session, pid);
899
            OutputStream out = response.getOutputStream();
900
            response.setStatus(200);
901
            response.setContentType("text/xml");
902
            // send back the reserved pid
903
            TypeMarshaller.marshalTypeToOutputStream(resultPid, out);
904
            
905
        } catch (IOException e) {
906
            String msg = "Couldn't write the identifier to the response output stream: " +
907
                e.getMessage();
908
            logMetacat.debug(msg);
909
            throw new ServiceFailure("4210", msg);
910
        
911
        } catch (JiBXException e) {
912
            String msg = "Couldn't marshall the identifier to the response output stream: " +
913
            e.getMessage();
914
            logMetacat.debug(msg);
915
            throw new ServiceFailure("4210", msg);
916
            
917
        }
918
    }
919

    
920
    /**
921
     * 
922
     * @param id
923
     * @throws InvalidRequest
924
     * @throws InvalidToken
925
     * @throws ServiceFailure
926
     * @throws NotAuthorized
927
     * @throws NotFound
928
     * @throws NotImplemented
929
     * @throws IOException
930
     * @throws JiBXException
931
     */
932
    private void resolve(String id) throws InvalidRequest, InvalidToken,
933
            ServiceFailure, NotAuthorized, NotFound, NotImplemented,
934
            IOException, JiBXException {
935
        Identifier pid = new Identifier();
936
        pid.setValue(id);
937
        ObjectLocationList locationList = CNodeService.getInstance(request)
938
                .resolve(session, pid);
939
        OutputStream out = response.getOutputStream();
940
        response.setStatus(200);
941
        response.setContentType("text/xml");
942
        TypeMarshaller.marshalTypeToOutputStream(locationList, out);
943

    
944
    }
945

    
946
    /**
947
     * Set the owner of a resource
948
     * 
949
     * @param id
950
     * @throws InvalidToken
951
     * @throws ServiceFailure
952
     * @throws NotFound
953
     * @throws NotAuthorized
954
     * @throws NotImplemented
955
     * @throws InvalidRequest
956
     * @throws IllegalAccessException
957
     * @throws InstantiationException
958
     * @throws VersionMismatch 
959
     */
960
    private void owner(String id) 
961
        throws InvalidToken, ServiceFailure, NotFound, NotAuthorized, 
962
        NotImplemented, InvalidRequest, InstantiationException, 
963
        IllegalAccessException, VersionMismatch {
964

    
965
        Identifier pid = new Identifier();
966
        pid.setValue(id);
967

    
968
        long serialVersion = 0L;
969
        String serialVersionStr = null;
970
        String userIdStr = null;
971
        Subject userId = null;
972
        
973
        // Parse the params out of the multipart form data
974
        // Read the incoming data from its Mime Multipart encoding
975
        logMetacat.debug("Parsing rights holder parameters from the mime multipart entity");
976
        try {
977
            collectMultipartParams();
978
            
979
        } catch (FileUploadException e1) {
980
            String msg = "FileUploadException: Couldn't parse the mime multipart information: " +
981
            e1.getMessage();
982
            logMetacat.debug(msg);
983
            throw new ServiceFailure("4490", msg);
984

    
985
        } catch (IOException e1) {
986
            String msg = "IOException: Couldn't parse the mime multipart information: " +
987
            e1.getMessage();
988
            logMetacat.debug(msg);
989
            throw new ServiceFailure("4490", msg);
990
        
991
        } catch (Exception e1) {
992
            String msg = "Exception: Couldn't parse the mime multipart information: " +
993
            e1.getMessage();
994
            logMetacat.debug(msg);
995
            throw new ServiceFailure("4490", msg);
996

    
997
        }
998
        
999
        // get the serialVersion
1000
        try {
1001
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1002
            serialVersion = new Long(serialVersionStr).longValue();
1003
            
1004
        } catch (NumberFormatException nfe) {
1005
            String msg = "The 'serialVersion' must be provided as a positive integer and was not.";
1006
            logMetacat.error(msg);
1007
            throw new InvalidRequest("4442", msg);
1008
                        
1009
        } catch (NullPointerException e) {
1010
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1011
            logMetacat.error(msg);
1012
            throw new InvalidRequest("4442", msg);
1013
            
1014
        }
1015

    
1016
        // get the subject userId that will become the rights holder
1017
        try {
1018
            userIdStr = multipartparams.get("userId").get(0);
1019
            userId = new Subject();
1020
            userId.setValue(userIdStr);
1021
                                    
1022
        } catch (NullPointerException e) {
1023
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1024
            logMetacat.error(msg);
1025
            throw new InvalidRequest("4442", msg);
1026
            
1027
        }
1028

    
1029
        // set the rights holder
1030
        Identifier retPid = CNodeService.getInstance(request).setRightsHolder(session, pid, userId, serialVersion);
1031
        
1032
        try {
1033
            OutputStream out = response.getOutputStream();
1034
            response.setStatus(200);
1035
            response.setContentType("text/xml");
1036
            TypeMarshaller.marshalTypeToOutputStream(retPid, out);
1037
            
1038
        } catch (IOException e) {
1039
            String msg = "Couldn't write the identifier to the response output stream: " +
1040
                e.getMessage();
1041
            logMetacat.debug(msg);
1042
            throw new ServiceFailure("4490", msg);
1043
        
1044
        } catch (JiBXException e) {
1045
            String msg = "Couldn't marshall the identifier to the response output stream: " +
1046
            e.getMessage();
1047
            logMetacat.debug(msg);
1048
            throw new ServiceFailure("4490", msg);
1049
            
1050
        }
1051
    }
1052

    
1053
    /**
1054
     * Processes the authorization check for given id
1055
     * 
1056
     * @param id
1057
     * @return
1058
     * @throws ServiceFailure
1059
     * @throws InvalidToken
1060
     * @throws NotFound
1061
     * @throws NotAuthorized
1062
     * @throws NotImplemented
1063
     * @throws InvalidRequest
1064
     */
1065
    private boolean isAuthorized(String id) throws ServiceFailure,
1066
            InvalidToken, NotFound, NotAuthorized, NotImplemented,
1067
            InvalidRequest {
1068
        Identifier pid = new Identifier();
1069
        pid.setValue(id);
1070
        String permission = params.get("action")[0];
1071
        boolean result = CNodeService.getInstance(request).isAuthorized(
1072
                session, pid, Permission.convert(permission));
1073
        response.setStatus(200);
1074
        response.setContentType("text/xml");
1075
        return result;
1076
    }
1077

    
1078
    /**
1079
     * Register System Metadata without data or metadata object
1080
     * 
1081
     * @param pid
1082
     *            identifier for System Metadata entry
1083
     * @throws JiBXException
1084
     * @throws FileUploadException
1085
     * @throws IOException
1086
     * @throws InvalidRequest
1087
     * @throws ServiceFailure
1088
     * @throws InvalidSystemMetadata
1089
     * @throws NotAuthorized
1090
     * @throws NotImplemented
1091
     * @throws IllegalAccessException
1092
     * @throws InstantiationException
1093
     * @throws InvalidToken 
1094
     */
1095
    protected void registerSystemMetadata()
1096
            throws ServiceFailure, InvalidRequest, IOException,
1097
            FileUploadException, JiBXException, NotImplemented, NotAuthorized,
1098
            InvalidSystemMetadata, InstantiationException,
1099
            IllegalAccessException, InvalidToken {
1100
    	
1101
    	// Read the incoming data from its Mime Multipart encoding
1102
        Map<String, File> files = collectMultipartFiles();
1103
        
1104
    	// get the encoded pid string from the body and make the object
1105
        String pidString = multipartparams.get("pid").get(0);
1106
        Identifier pid = new Identifier();
1107
        pid.setValue(pidString);
1108
        
1109
        logMetacat.debug("registerSystemMetadata: " + pid);
1110

    
1111
        // get the system metadata from the request
1112
        File smFile = files.get("sysmeta");
1113
        FileInputStream sysmeta = new FileInputStream(smFile);
1114
        SystemMetadata systemMetadata = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysmeta);
1115

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

    
1119
        OutputStream out = response.getOutputStream();
1120
        response.setStatus(200);
1121
        response.setContentType("text/xml");
1122
        
1123
        TypeMarshaller.marshalTypeToOutputStream(retGuid, out);
1124

    
1125
    }
1126

    
1127
    /**
1128
     * set the access perms on a document
1129
     * 
1130
     * @throws JiBXException
1131
     * @throws InvalidRequest
1132
     * @throws NotImplemented
1133
     * @throws NotAuthorized
1134
     * @throws NotFound
1135
     * @throws ServiceFailure
1136
     * @throws InvalidToken
1137
     * @throws IllegalAccessException
1138
     * @throws InstantiationException
1139
     * @throws IOException
1140
     * @throws SAXException
1141
     * @throws ParserConfigurationException
1142
     * @throws VersionMismatch 
1143
     */
1144
    protected void setAccess(String pid) throws JiBXException, InvalidToken,
1145
            ServiceFailure, NotFound, NotAuthorized, NotImplemented,
1146
            InvalidRequest, IOException, InstantiationException,
1147
            IllegalAccessException, ParserConfigurationException, SAXException, VersionMismatch {
1148

    
1149
        long serialVersion = 0L;
1150
        String serialVersionStr = null;
1151
        
1152
        // parse the accessPolicy
1153
        Map<String, File> files = collectMultipartFiles();        
1154
        AccessPolicy accessPolicy = TypeMarshaller.unmarshalTypeFromFile(AccessPolicy.class, files.get("accessPolicy"));;
1155

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

    
1161
        } catch (NumberFormatException nfe) {
1162
            String msg = "The 'serialVersion' must be provided as a positive integer and was not.";
1163
            logMetacat.error(msg);
1164
            throw new InvalidRequest("4402", msg);
1165
            
1166
        } catch (NullPointerException e) {
1167
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1168
            logMetacat.error(msg);
1169
            throw new InvalidRequest("4402", msg);
1170

    
1171
        }
1172

    
1173
        Identifier id = new Identifier();
1174
        id.setValue(pid);
1175

    
1176
        CNodeService.getInstance(request).setAccessPolicy(session, id,
1177
                accessPolicy, serialVersion);
1178

    
1179
    }
1180

    
1181
    /**
1182
     * List the objects
1183
     * 
1184
     * @throws NotImplemented
1185
     * @throws InvalidRequest
1186
     * @throws NotAuthorized
1187
     * @throws ServiceFailure
1188
     * @throws InvalidToken
1189
     * @throws NotFound
1190
     * @throws IOException
1191
     * @throws JiBXException
1192
     * @throws Exception
1193
     */
1194
    private void listObjects() throws InvalidToken, ServiceFailure,
1195
            NotAuthorized, InvalidRequest, NotImplemented, NotFound,
1196
            IOException, JiBXException {
1197

    
1198
        Date startTime = null;
1199
        Date endTime = null;
1200
        ObjectFormatIdentifier formatId = null;
1201
        boolean replicaStatus = true;
1202
        int start = 0;
1203
        int count = 1000;
1204
        Enumeration<String> paramlist = request.getParameterNames();
1205
        while (paramlist.hasMoreElements()) {
1206
            // parse the params and make the call
1207
            String name = paramlist.nextElement();
1208
            String[] values = request.getParameterValues(name);
1209
            String value = null;
1210
            if (values != null && values.length > 0) {
1211
            	value = values[0];
1212
            	value = EncodingUtilities.decodeString(value);
1213
            }
1214

    
1215
            if (name.equals("fromDate") && value != null) {
1216
                try {
1217
                    startTime = DateTimeMarshaller.deserializeDateToUTC(value);
1218
                } catch (Exception e) {
1219
                    // if we can't parse it, just don't use the startTime param
1220
                    logMetacat.warn("Could not parse fromDate: " + value);
1221
                    startTime = null;
1222
                }
1223
            } else if (name.equals("toDate") && value != null) {
1224
                try {
1225
                    endTime = DateTimeMarshaller.deserializeDateToUTC(value);
1226
                } catch (Exception e) {
1227
                    // if we can't parse it, just don't use the endTime param
1228
                    logMetacat.warn("Could not parse toDate: " + value);
1229
                    endTime = null;
1230
                }
1231
            } else if (name.equals("formatId") && value != null) {
1232
            	formatId = new ObjectFormatIdentifier();
1233
            	formatId.setValue(value);
1234
            } else if (name.equals("replicaStatus") && value != null) {
1235
                replicaStatus = Boolean.parseBoolean(value);
1236
            } else if (name.equals("start") && value != null) {
1237
                start = Integer.valueOf(value);
1238
            } else if (name.equals("count") && value != null) {
1239
                count = Integer.valueOf(value);
1240
            }
1241
        }
1242
        // make the call
1243
        logMetacat.debug("session: " + session + " fromDate: " + startTime
1244
                + " toDate: " + endTime + " formatId: " + formatId
1245
                + " replicaStatus: " + replicaStatus + " start: " + start
1246
                + " count: " + count);        
1247

    
1248
        // get the list
1249
        ObjectList ol = CNodeService.getInstance(request).listObjects(session,
1250
                startTime, endTime, formatId, replicaStatus, start, count);
1251

    
1252
        // send it
1253
        OutputStream out = response.getOutputStream();
1254
        response.setStatus(200);
1255
        response.setContentType("text/xml");
1256

    
1257
        // style the object with a processing directive
1258
        String stylesheet = null;
1259
        try {
1260
            stylesheet = PropertyService.getProperty("dataone.types.xsl");
1261
        } catch (PropertyNotFoundException e) {
1262
            logMetacat.warn("Could not locate DataONE types XSLT: "
1263
                    + e.getMessage());
1264
        }
1265

    
1266
        // Serialize and write it to the output stream
1267
        TypeMarshaller.marshalTypeToOutputStream(ol, out, stylesheet);
1268
    }
1269

    
1270
    /**
1271
     * Pass the request to get node replication authorization to CNodeService
1272
     * 
1273
     * @param pid
1274
     *            the identifier of the object to get authorization to replicate
1275
     * 
1276
     * @throws NotImplemented
1277
     * @throws NotAuthorized
1278
     * @throws InvalidToken
1279
     * @throws ServiceFailure
1280
     * @throws NotFound
1281
     * @throws InvalidRequest
1282
     */
1283
    public boolean isNodeAuthorized(String pid) throws NotImplemented,
1284
            NotAuthorized, InvalidToken, ServiceFailure, NotFound,
1285
            InvalidRequest {
1286

    
1287
        boolean result = false;
1288
        Subject targetNodeSubject = new Subject();
1289
        String nodeSubject = null;
1290
        String replPermission = null;
1291

    
1292
        // get the pid
1293
        Identifier identifier = new Identifier();
1294
        identifier.setValue(pid);
1295

    
1296
        // get the target node subject
1297
        try {
1298
            nodeSubject = params.get("targetNodeSubject")[0];
1299
            targetNodeSubject.setValue(nodeSubject);
1300

    
1301
        } catch (NullPointerException e) {
1302
            String msg = "The 'targetNodeSubject' must be provided as a parameter and was not.";
1303
            logMetacat.error(msg);
1304
            throw new InvalidRequest("4873", msg);
1305

    
1306
        }
1307

    
1308
        result = CNodeService.getInstance(request).isNodeAuthorized(session, targetNodeSubject, identifier);
1309

    
1310
        response.setStatus(200);
1311
        response.setContentType("text/xml");
1312
        return result;
1313

    
1314
    }
1315

    
1316
    /**
1317
     * Pass the request to set the replication policy to CNodeService
1318
     * 
1319
     * @param pid
1320
     *            the identifier of the object to set the replication policy on
1321
     * 
1322
     * @throws NotImplemented
1323
     * @throws NotFound
1324
     * @throws NotAuthorized
1325
     * @throws ServiceFailure
1326
     * @throws InvalidRequest
1327
     * @throws InvalidToken
1328
     * @throws IOException
1329
     * @throws InstantiationException
1330
     * @throws IllegalAccessException
1331
     * @throws JiBXException
1332
     * @throws VersionMismatch 
1333
     */
1334
    public boolean setReplicationPolicy(String pid) throws NotImplemented,
1335
            NotFound, NotAuthorized, ServiceFailure, InvalidRequest,
1336
            InvalidToken, IOException, InstantiationException,
1337
            IllegalAccessException, JiBXException, VersionMismatch {
1338

    
1339
        boolean result = false;
1340
        long serialVersion = 0L;
1341
        String serialVersionStr = null;
1342

    
1343
        Identifier identifier = new Identifier();
1344
        identifier.setValue(pid);
1345

    
1346
        // parse the policy
1347
        Map<String, File> files = collectMultipartFiles();        
1348
        ReplicationPolicy policy = TypeMarshaller.unmarshalTypeFromFile(ReplicationPolicy.class, files.get("policy"));
1349

    
1350
        // get the serialVersion
1351
        try {
1352
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1353
            serialVersion = new Long(serialVersionStr).longValue();
1354

    
1355
        } catch (NullPointerException e) {
1356
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1357
            logMetacat.error(msg);
1358
            throw new InvalidRequest("4883", msg);
1359

    
1360
        }
1361
        result = CNodeService.getInstance(request).setReplicationPolicy(
1362
                session, identifier, policy, serialVersion);
1363
        response.setStatus(200);
1364
        response.setContentType("text/xml");
1365
        return result;
1366

    
1367
    }
1368
    
1369
    /**
1370
     * Update the system metadata for a given pid, setting it to be obsoleted
1371
     * by the obsoletedByPid
1372
     *  
1373
     * @param pid
1374
     * @return
1375
     * @throws NotImplemented
1376
     * @throws NotFound
1377
     * @throws NotAuthorized
1378
     * @throws ServiceFailure
1379
     * @throws InvalidRequest
1380
     * @throws InvalidToken
1381
     * @throws InstantiationException
1382
     * @throws IllegalAccessException
1383
     * @throws VersionMismatch
1384
     */
1385
    public boolean setObsoletedBy(String pid) 
1386
        throws NotImplemented, NotFound, NotAuthorized, ServiceFailure, 
1387
        InvalidRequest, InvalidToken, InstantiationException, 
1388
        IllegalAccessException, VersionMismatch {
1389

    
1390
        boolean result = false;
1391
        long serialVersion = 0L;
1392
        String serialVersionStr = null;
1393

    
1394
        Identifier identifier = new Identifier();
1395
        identifier.setValue(pid);
1396
        String obsoletedByPidString = null;
1397
        Identifier obsoletedByPid = null;
1398

    
1399
        // Parse the params out of the multipart form data
1400
        // Read the incoming data from its Mime Multipart encoding
1401
        logMetacat.debug("Parsing rights holder parameters from the mime multipart entity");
1402
        try {
1403
            collectMultipartParams();
1404
            
1405
        } catch (FileUploadException e1) {
1406
            String msg = "FileUploadException: Couldn't parse the mime multipart information: " +
1407
            e1.getMessage();
1408
            logMetacat.debug(msg);
1409
            throw new ServiceFailure("4941", msg);
1410

    
1411
        } catch (IOException e1) {
1412
            String msg = "IOException: Couldn't parse the mime multipart information: " +
1413
            e1.getMessage();
1414
            logMetacat.debug(msg);
1415
            throw new ServiceFailure("4941", msg);
1416
        
1417
        } catch (Exception e1) {
1418
            String msg = "Exception: Couldn't parse the mime multipart information: " +
1419
            e1.getMessage();
1420
            logMetacat.debug(msg);
1421
            throw new ServiceFailure("4941", msg);
1422

    
1423
        }
1424

    
1425
        // get the obsoletedByPid
1426
        try {
1427
            obsoletedByPidString = multipartparams.get("obsoletedByPid").get(0);
1428
            obsoletedByPid = new Identifier();
1429
            obsoletedByPid.setValue(obsoletedByPidString);
1430
        } catch (NullPointerException e) {
1431
            String msg = "The 'obsoletedByPid' must be provided as a parameter and was not.";
1432
            logMetacat.error(msg);
1433
            throw new InvalidRequest("4883", msg);
1434
        }
1435

    
1436
        // get the serialVersion
1437
        try {
1438
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1439
            serialVersion = new Long(serialVersionStr).longValue();
1440
            
1441
        } catch (NumberFormatException nfe) {
1442
            String msg = "The 'serialVersion' must be provided as a positive integer and was not.";
1443
            logMetacat.error(msg);
1444
            throw new InvalidRequest("4942", msg);
1445
                        
1446
        } catch (NullPointerException e) {
1447
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1448
            logMetacat.error(msg);
1449
            throw new InvalidRequest("4942", msg);
1450
            
1451
        }
1452
        result = CNodeService.getInstance(request).setObsoletedBy(session,
1453
            identifier, obsoletedByPid, serialVersion);
1454
        response.setStatus(200);
1455
        response.setContentType("text/xml");
1456
        return result;
1457

    
1458
    }
1459
    
1460
    /**
1461
     * Delete the replica entry with the given nodeId for the given pid
1462
     * 
1463
     * @param pid
1464
     * @return
1465
     * @throws NotImplemented
1466
     * @throws NotFound
1467
     * @throws NotAuthorized
1468
     * @throws ServiceFailure
1469
     * @throws InvalidRequest
1470
     * @throws InvalidToken
1471
     * @throws InstantiationException
1472
     * @throws IllegalAccessException
1473
     * @throws VersionMismatch
1474
     */
1475
    public boolean deleteReplica(String pid) 
1476
        throws NotImplemented, NotFound, NotAuthorized, ServiceFailure, 
1477
        InvalidRequest, InvalidToken, InstantiationException, 
1478
        IllegalAccessException, VersionMismatch {
1479

    
1480
        boolean result = false;
1481
        long serialVersion = 0L;
1482
        String serialVersionStr = null;
1483

    
1484
        Identifier identifier = new Identifier();
1485
        identifier.setValue(pid);
1486

    
1487
        NodeReference nodeId = null;
1488
        
1489
        // Parse the params out of the multipart form data
1490
        // Read the incoming data from its Mime Multipart encoding
1491
        logMetacat.debug("Parsing delete replica parameters from the mime multipart entity");
1492
        try {
1493
            collectMultipartParams();
1494
            
1495
        } catch (FileUploadException e1) {
1496
            String msg = "FileUploadException: Couldn't parse the mime multipart information: " +
1497
            e1.getMessage();
1498
            logMetacat.debug(msg);
1499
            throw new ServiceFailure("4951", msg);
1500

    
1501
        } catch (IOException e1) {
1502
            String msg = "IOException: Couldn't parse the mime multipart information: " +
1503
            e1.getMessage();
1504
            logMetacat.debug(msg);
1505
            throw new ServiceFailure("4951", msg);
1506
        
1507
        } catch (Exception e1) {
1508
            String msg = "Exception: Couldn't parse the mime multipart information: " +
1509
            e1.getMessage();
1510
            logMetacat.debug(msg);
1511
            throw new ServiceFailure("4951", msg);
1512

    
1513
        }
1514
        
1515
        // get the nodeId param
1516
        try {
1517
            String nodeIdString = multipartparams.get("nodeId").get(0);
1518
            nodeId = new NodeReference();
1519
            nodeId.setValue(nodeIdString);
1520
            
1521
        } catch (NullPointerException e) {
1522
            String msg = "The 'nodeId' must be provided as a parameter and was not.";
1523
            logMetacat.error(msg);
1524
            throw new InvalidRequest("4952", msg);
1525
        }
1526

    
1527
        // get the serialVersion
1528
        try {
1529
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1530
            serialVersion = new Long(serialVersionStr).longValue();
1531
            
1532
        } catch (NumberFormatException nfe) {
1533
            String msg = "The 'serialVersion' must be provided as a positive integer and was not.";
1534
            logMetacat.error(msg);
1535
            throw new InvalidRequest("4952", msg);
1536
                        
1537
        } catch (NullPointerException e) {
1538
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1539
            logMetacat.error(msg);
1540
            throw new InvalidRequest("4952", msg);
1541
            
1542
        }
1543
        result = CNodeService.getInstance(request).deleteReplicationMetadata(
1544
                session, identifier, nodeId, serialVersion);
1545
        response.setStatus(200);
1546
        response.setContentType("text/xml");
1547
        return result;
1548

    
1549
    }
1550

    
1551
    /**
1552
     * Pass the request to set the replication status to CNodeService
1553
     * 
1554
     * @param pid
1555
     *            the identifier of the object to set the replication status on
1556
     * 
1557
     * @throws ServiceFailure
1558
     * @throws NotImplemented
1559
     * @throws InvalidToken
1560
     * @throws NotAuthorized
1561
     * @throws InvalidRequest
1562
     * @throws NotFound
1563
     * @throws JiBXException 
1564
     * @throws IllegalAccessException 
1565
     * @throws InstantiationException 
1566
     * @throws IOException 
1567
     */
1568
    public boolean setReplicationStatus(String pid) throws ServiceFailure,
1569
            NotImplemented, InvalidToken, NotAuthorized, InvalidRequest,
1570
            NotFound {
1571
        
1572
        boolean result = false;
1573
        Identifier identifier = new Identifier();
1574
        identifier.setValue(pid);
1575
        BaseException failure = null;
1576
        ReplicationStatus status = null;
1577
        String replicationStatus = null;
1578
        NodeReference targetNodeRef = null;
1579
        String targetNode = null;
1580

    
1581
        // Parse the params out of the multipart form data
1582
        // Read the incoming data from its Mime Multipart encoding
1583
        logMetacat.debug("Parsing ReplicaStatus from the mime multipart entity");
1584

    
1585
        try {
1586
        	// parse the policy
1587
            Map<String, File> files = collectMultipartFiles();        
1588
            failure = ExceptionHandler.deserializeXml(new FileInputStream(files.get("failure")), 
1589
                    "Replication failed for an unknown reason.");
1590
            
1591
        } catch (Exception e2) {
1592
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1593
                e2.getMessage());
1594
            
1595
        }
1596
        
1597
        // get the replication status param
1598
        try {
1599
            replicationStatus = multipartparams.get("status").get(0);
1600
            status = ReplicationStatus.convert(replicationStatus);
1601

    
1602
        } catch (NullPointerException npe) {
1603

    
1604
            logMetacat.debug("The 'status' parameter was not found in the "
1605
                    + "multipartparams map.  Trying the params map.");
1606

    
1607
            try {
1608
                replicationStatus = params.get("status")[0];
1609
                status = ReplicationStatus.convert(replicationStatus
1610
                        .toLowerCase());
1611

    
1612
            } catch (Exception e) {
1613
                String msg = "The 'status' must be provided as a parameter and was not.";
1614
                logMetacat.error(msg);
1615
                throw new InvalidRequest("4730", msg);
1616

    
1617
            }
1618

    
1619
        }
1620

    
1621
        // get the target node reference param
1622
        try {
1623
            targetNode = multipartparams.get("nodeRef").get(0);
1624
            targetNodeRef = new NodeReference();
1625
            targetNodeRef.setValue(targetNode);
1626

    
1627
        } catch (NullPointerException e) {
1628
            logMetacat.debug("The 'nodeRef' parameter was not found in the "
1629
                    + "multipartparams map.  Trying the params map.");
1630

    
1631
            try {
1632
                targetNode = params.get("nodeRef")[0];
1633
                targetNodeRef = new NodeReference();
1634
                targetNodeRef.setValue(targetNode);
1635

    
1636
            } catch (Exception e1) {
1637
                String msg = "The 'nodeRef' must be provided as a parameter and was not.";
1638
                logMetacat.error(msg);
1639
                throw new InvalidRequest("4730", msg);
1640

    
1641
            }
1642

    
1643
        }
1644

    
1645
        result = CNodeService.getInstance(request).setReplicationStatus(
1646
                session, identifier, targetNodeRef, status, failure);
1647
        response.setStatus(200);
1648
        response.setContentType("text/xml");
1649
        return result;
1650

    
1651
    }
1652

    
1653
    /**
1654
     * Pass the request to update the replication metadata to CNodeService
1655
     * 
1656
     * @param pid
1657
     *            the identifier of the object to update the replication
1658
     *            metadata on
1659
     * 
1660
     * @throws ServiceFailure
1661
     * @throws NotImplemented
1662
     * @throws InvalidToken
1663
     * @throws NotAuthorized
1664
     * @throws InvalidRequest
1665
     * @throws NotFound
1666
     * @throws VersionMismatch 
1667
     * @throws JiBXException 
1668
     * @throws IOException 
1669
     * @throws IllegalAccessException 
1670
     * @throws InstantiationException 
1671
     */
1672
    public boolean updateReplicationMetadata(String pid) throws ServiceFailure,
1673
            NotImplemented, InvalidToken, NotAuthorized, InvalidRequest,
1674
            NotFound, VersionMismatch, InstantiationException, IllegalAccessException, IOException, JiBXException {
1675

    
1676
        boolean result = false;
1677
        long serialVersion = 0L;
1678
        String serialVersionStr = null;
1679
        Identifier identifier = new Identifier();
1680
        identifier.setValue(pid);
1681

    
1682
        // parse the replica
1683
        Map<String, File> files = collectMultipartFiles();        
1684
        Replica replica = TypeMarshaller.unmarshalTypeFromFile(Replica.class, files.get("replicaMetadata"));
1685

    
1686
        // get the serialVersion
1687
        try {
1688
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1689
            serialVersion = new Long(serialVersionStr).longValue();
1690

    
1691
        } catch (NullPointerException e) {
1692
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1693
            logMetacat.error(msg);
1694
            throw new InvalidRequest("4853", msg);
1695

    
1696
        }
1697

    
1698
        result = CNodeService.getInstance(request).updateReplicationMetadata(
1699
                session, identifier, replica, serialVersion);
1700
        response.setStatus(200);
1701
        response.setContentType("text/xml");
1702
        return result;
1703

    
1704
    }
1705

    
1706
}
(1-1/4)