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: 2015-07-09 14:09:18 -0700 (Thu, 09 Jul 2015) $'
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.v2;
24

    
25
import java.io.File;
26
import java.io.FileInputStream;
27
import java.io.FileNotFoundException;
28
import java.io.IOException;
29
import java.io.InputStream;
30
import java.io.OutputStream;
31
import java.util.Date;
32
import java.util.Enumeration;
33
import java.util.Map;
34

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

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

    
84
import edu.ucsb.nceas.metacat.common.query.stream.ContentTypeInputStream;
85
import edu.ucsb.nceas.metacat.dataone.CNodeService;
86
import edu.ucsb.nceas.metacat.properties.PropertyService;
87
import edu.ucsb.nceas.metacat.restservice.D1ResourceHandler;
88
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
89

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

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

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

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

    
148
        try {
149

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

    
161
            // for the rest of the resouce
162
            String extra = null;
163

    
164
            logMetacat.debug("handling verb " + httpVerb
165
                    + " request with resource '" + resource + "'");
166
            boolean status = false;
167

    
168
            if (resource != null) {
169

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

    
179
                } else if (resource.startsWith(RESOURCE_META)) {
180
                    logMetacat.debug("Using resource: " + RESOURCE_META);
181

    
182
                    // after the command
183
                    extra = parseTrailing(resource, RESOURCE_META);
184

    
185
                    // get
186
                    if (httpVerb == GET) {
187
                        getSystemMetadataObject(extra);
188
                        status = true;
189
                    }
190
                    // post to register system metadata
191
                    if (httpVerb == POST) {
192
                        registerSystemMetadata();
193
                        status = true;
194
                    }
195
                    else if (httpVerb == PUT) {
196
                        logMetacat.debug("Using resource 'meta' for PUT");
197
                        updateSystemMetadata();
198
                        status = true;
199
                    }
200

    
201
                } else if (resource.startsWith(RESOURCE_RESERVE)) {
202
                    // reserve the ID (in params)
203
                    if (httpVerb == POST) {
204
                        reserve();
205
                        status = true;
206
                    }
207
                } else if (resource.startsWith(RESOURCE_RESOLVE)) {
208

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

    
212
                    // resolve the object location
213
                    if (httpVerb == GET) {
214
                        resolve(extra);
215
                        status = true;
216
                    }
217
                } else if (resource.startsWith(RESOURCE_OWNER)) {
218

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

    
222
                    // set the owner
223
                    if (httpVerb == PUT) {
224
                        owner(extra);
225
                        status = true;
226
                    }
227
                } else if (resource.startsWith(RESOURCE_IS_AUTHORIZED)) {
228

    
229
                    // after the command
230
                    extra = parseTrailing(resource, RESOURCE_IS_AUTHORIZED);
231

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

    
242
                    // after the command
243
                    extra = parseTrailing(resource, RESOURCE_OBJECTS);
244

    
245
                    logMetacat.debug("objectId: " + extra);
246
                    logMetacat.debug("verb:" + httpVerb);
247

    
248
                    if (httpVerb == GET) {
249
                        if (extra != null) {
250
                            getObject(extra);
251
                        } else {
252
                            listObjects();
253
                        }
254
                        status = true;
255
                    } else if (httpVerb == POST) {
256
                        putObject(FUNCTION_NAME_INSERT);
257
                        status = true;
258
                    } else if (httpVerb == HEAD) {
259
                        describeObject(extra);
260
                        status = true;
261
                    } else if (httpVerb == DELETE) {
262
                        deleteObject(extra);
263
                        status = true;
264
                    } 
265

    
266
                } else if (resource.startsWith(RESOURCE_FORMATS)) {
267
                    logMetacat.debug("Using resource: " + RESOURCE_FORMATS);
268

    
269
                    // after the command
270
                    extra = parseTrailing(resource, RESOURCE_FORMATS);
271

    
272
                    // handle each verb
273
                    if (httpVerb == GET) {
274
                        if (extra == null) {
275
                            // list the formats collection
276
                            listFormats();
277
                        } else {
278
                            // get the specified format
279
                            getFormat(extra);
280
                        }
281
                        status = true;
282
                    } else if (httpVerb == PUT) {
283
                        addFormat(extra);
284
                    }
285

    
286
                } else if (resource.startsWith(RESOURCE_LOG)) {
287
                    logMetacat.debug("Using resource: " + RESOURCE_LOG);
288
                    // handle log events
289
                    if (httpVerb == GET) {
290
                        getLog();
291
                        status = true;
292
                    }
293

    
294
                } else if (resource.startsWith(Constants.RESOURCE_ARCHIVE)) {
295
                    logMetacat.debug("Using resource " + Constants.RESOURCE_ARCHIVE);
296
                    // handle archive events
297
                    if (httpVerb == PUT) {
298
                        extra = parseTrailing(resource, Constants.RESOURCE_ARCHIVE);
299
                        archive(extra);
300
                        status = true;
301
                    }
302
                } else if (resource.startsWith(Constants.RESOURCE_CHECKSUM)) {
303
                    logMetacat.debug("Using resource: " + Constants.RESOURCE_CHECKSUM);
304

    
305
                    // after the command
306
                    extra = parseTrailing(resource, Constants.RESOURCE_CHECKSUM);
307

    
308
                    // handle checksum requests
309
                    if (httpVerb == GET) {
310

    
311
                    	if (extra != null && extra.length() > 0) {
312
	                        checksum(extra);
313
	                        status = true;
314
                    	} else {
315
                    		listChecksumAlgorithms();
316
                    		status = true;
317
                    	}
318

    
319
                    }
320

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

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

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

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

    
341
                } else if (resource.startsWith(RESOURCE_REPLICATION_NOTIFY)
342
                        && httpVerb == PUT) {
343

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

    
351
                } else if (resource.startsWith(RESOURCE_REPLICATION_AUTHORIZED)
352
                        && httpVerb == GET) {
353

    
354
                    logMetacat.debug("Using resource: "
355
                            + RESOURCE_REPLICATION_AUTHORIZED);
356
                    // get the trailing pid
357
                    extra = parseTrailing(resource,
358
                            RESOURCE_REPLICATION_AUTHORIZED);
359
                    isNodeAuthorized(extra);
360
                    status = true;
361

    
362
                } else if (resource.startsWith(Constants.RESOURCE_MONITOR_PING)) {
363
                    if (httpVerb == GET) {
364
                    	// after the command
365
                        extra = parseTrailing(resource, Constants.RESOURCE_MONITOR_PING);
366
                        
367
                        logMetacat.debug("processing ping request");
368
                        Date result = CNodeService.getInstance(request).ping();
369
                        // TODO: send to output	
370
                        status = true;
371
                    }
372
                } else if (resource.startsWith(Constants.RESOURCE_META_OBSOLETEDBY)
373
                        && httpVerb == PUT) {
374

    
375
                    logMetacat.debug("Using resource: "
376
                            + Constants.RESOURCE_META_OBSOLETEDBY);
377
                    // get the trailing pid
378
                    extra = parseTrailing(resource, Constants.RESOURCE_META_OBSOLETEDBY);
379
                    setObsoletedBy(extra);
380
                    status = true;
381
                } else if (resource.startsWith(Constants.RESOURCE_REPLICATION_DELETE_REPLICA)
382
                        && httpVerb == PUT) {
383

    
384
                    logMetacat.debug("Using resource: "
385
                            + Constants.RESOURCE_REPLICATION_DELETE_REPLICA);
386
                    // get the trailing pid
387
                    extra = parseTrailing(resource, Constants.RESOURCE_REPLICATION_DELETE_REPLICA);
388
                    deleteReplica(extra);
389
                    status = true;
390
                } else if (resource.startsWith(RESOURCE_VIEWS)) {
391
                    logMetacat.debug("Using resource " + RESOURCE_VIEWS);
392
                    // after the command
393
                    extra = parseTrailing(resource, RESOURCE_VIEWS);
394
                    logMetacat.debug("view extra: " + extra);
395

    
396
                    String format = null;
397
                    String pid = null;
398

    
399
                    if (extra != null) {
400
                        // get the format
401
                        int formatIndex = extra.length();
402
                        if (extra.indexOf("/") > -1) {
403
                            formatIndex = extra.indexOf("/");
404
                        }
405
                        format = extra.substring(0, formatIndex);
406
                        logMetacat.debug("view format: " + format);
407
                        
408
                        // get the pid if it is there
409
                        pid = extra.substring(formatIndex, extra.length());
410
                        if (pid != null && pid.length() == 0) {
411
                            pid = null;
412
                        } else {
413
                            if (pid.startsWith("/")) {
414
                                pid = pid.substring(1);
415
                            }
416
                        }
417
                        logMetacat.debug("pid: " + pid);
418

    
419
                    }
420
                    logMetacat.debug("verb:" + httpVerb);
421
                    if (httpVerb == GET) {
422
                        doViews(format, pid);
423
                        status = true;
424
                    }
425
                } 
426

    
427
                if (!status) {
428
                    throw new ServiceFailure("0000", "Unknown error, status = "
429
                            + status);
430
                }
431
            } else {
432
                throw new InvalidRequest("0000", "No resource matched for "
433
                        + resource);
434
            }
435
        } catch (BaseException be) {
436
            // report Exceptions as clearly and generically as possible
437
            OutputStream out = null;
438
            try {
439
                out = response.getOutputStream();
440
            } catch (IOException ioe) {
441
                logMetacat.error("Could not get output stream from response",
442
                        ioe);
443
            }
444
            serializeException(be, out);
445
        } catch (Exception e) {
446
            // report Exceptions as clearly and generically as possible
447
            logMetacat.error(e.getClass() + ": " + e.getMessage(), e);
448
            OutputStream out = null;
449
            try {
450
                out = response.getOutputStream();
451
            } catch (IOException ioe) {
452
                logMetacat.error("Could not get output stream from response",
453
                        ioe);
454
            }
455
            ServiceFailure se = new ServiceFailure("0000", e.getMessage());
456
            serializeException(se, out);
457
        }
458
    }
459

    
460
    /**
461
     * Get the checksum for the given guid
462
     * 
463
     * @param guid
464
     * @throws NotImplemented
465
     * @throws InvalidRequest
466
     * @throws NotFound
467
     * @throws NotAuthorized
468
     * @throws ServiceFailure
469
     * @throws InvalidToken
470
     * @throws IOException
471
     * @throws JiBXException
472
     */
473
    private void checksum(String guid) throws InvalidToken, ServiceFailure,
474
            NotAuthorized, NotFound, InvalidRequest, NotImplemented,
475
            JiBXException, IOException {
476
        Identifier guidid = new Identifier();
477
        guidid.setValue(guid);
478
        logMetacat.debug("getting checksum for object " + guid);
479
        Checksum c = CNodeService.getInstance(request).getChecksum(session,
480
                guidid);
481
        logMetacat.debug("got checksum " + c.getValue());
482
        response.setStatus(200);
483
        logMetacat.debug("serializing response");
484
        TypeMarshaller.marshalTypeToOutputStream(c, response.getOutputStream());
485
        logMetacat.debug("done serializing response.");
486

    
487
    }
488

    
489
    /**
490
     * get the logs based on passed params. Available params are token,
491
     * fromDate, toDate, event. See
492
     * http://mule1.dataone.org/ArchitectureDocs/mn_api_crud
493
     * .html#MN_crud.getLogRecords for more info
494
     * 
495
     * @throws NotImplemented
496
     * @throws InvalidRequest
497
     * @throws NotAuthorized
498
     * @throws ServiceFailure
499
     * @throws InvalidToken
500
     * @throws IOException
501
     * @throws JiBXException
502
     */
503
    private void getLog() throws InvalidToken, ServiceFailure, NotAuthorized,
504
            InvalidRequest, NotImplemented, IOException, JiBXException {
505

    
506
        Date fromDate = null;
507
        Date toDate = null;
508
        String event = null;
509
        Integer start = null;
510
        Integer count = null;
511
        String pidFilter = null;
512

    
513
        try {
514
            String fromDateS = params.get("fromDate")[0];
515
            logMetacat.debug("param fromDateS: " + fromDateS);
516
            fromDate = DateTimeMarshaller.deserializeDateToUTC(fromDateS);
517
        } catch (Exception e) {
518
            logMetacat.warn("Could not parse fromDate: " + e.getMessage());
519
        }
520
        try {
521
            String toDateS = params.get("toDate")[0];
522
            logMetacat.debug("param toDateS: " + toDateS);
523
            toDate = DateTimeMarshaller.deserializeDateToUTC(toDateS);
524
        } catch (Exception e) {
525
            logMetacat.warn("Could not parse toDate: " + e.getMessage());
526
        }
527
        try {
528
            event = params.get("event")[0];
529
        } catch (Exception e) {
530
            logMetacat.warn("Could not parse event: " + e.getMessage());
531
        }
532
        logMetacat.debug("fromDate: " + fromDate + " toDate: " + toDate);
533

    
534
        try {
535
            start = Integer.parseInt(params.get("start")[0]);
536
        } catch (Exception e) {
537
            logMetacat.warn("Could not parse start: " + e.getMessage());
538
        }
539
        try {
540
            count = Integer.parseInt(params.get("count")[0]);
541
        } catch (Exception e) {
542
            logMetacat.warn("Could not parse count: " + e.getMessage());
543
        }
544

    
545
        try {
546
            pidFilter = params.get("pidFilter")[0];
547
        } catch (Exception e) {
548
            logMetacat.warn("Could not parse pidFilter: " + e.getMessage());
549
        }
550
        
551
        logMetacat.debug("calling getLogRecords");
552
        Log log = CNodeService.getInstance(request).getLogRecords(session,
553
                fromDate, toDate, event, pidFilter, start, count);
554

    
555
        OutputStream out = response.getOutputStream();
556
        response.setStatus(200);
557
        response.setContentType("text/xml");
558

    
559
        TypeMarshaller.marshalTypeToOutputStream(log, out);
560

    
561
    }
562

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

    
580
        Identifier id = new Identifier();
581
        id.setValue(guid);
582

    
583
        SystemMetadata sm = CNodeService.getInstance(request)
584
                .getSystemMetadata(session, id);
585

    
586
        // set the headers for the content
587
        String mimeType = ObjectFormatInfo.instance().getMimeType(sm.getFormatId().getValue());
588
        if (mimeType == null) {
589
        	mimeType = "application/octet-stream";
590
        }
591
        String extension = ObjectFormatInfo.instance().getExtension(sm.getFormatId().getValue());
592
        String filename = id.getValue();
593
        if (extension != null) {
594
        	filename = id.getValue() + extension;
595
        }
596
        response.setContentType(mimeType);
597
        response.setHeader("Content-Disposition", "inline; filename=" + filename);
598

    
599
        InputStream data = CNodeService.getInstance(request).get(session, id);
600

    
601
        OutputStream out = response.getOutputStream();
602
        response.setStatus(200);
603
        IOUtils.copyLarge(data, out);
604

    
605
    }
606

    
607
    /**
608
     * Implements REST version of DataONE CRUD API --> getSystemMetadata
609
     * 
610
     * @param guid
611
     *            ID of data object to be read
612
     * @throws NotImplemented
613
     * @throws InvalidRequest
614
     * @throws NotFound
615
     * @throws NotAuthorized
616
     * @throws ServiceFailure
617
     * @throws InvalidToken
618
     * @throws IOException
619
     * @throws JiBXException
620
     */
621
    protected void getSystemMetadataObject(String guid) throws InvalidToken,
622
            ServiceFailure, NotAuthorized, NotFound, InvalidRequest,
623
            NotImplemented, IOException, JiBXException {
624

    
625
        Identifier id = new Identifier();
626
        id.setValue(guid);
627
        SystemMetadata sysmeta = CNodeService.getInstance(request)
628
                .getSystemMetadata(session, id);
629

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

    
634
        // Serialize and write it to the output stream
635
        TypeMarshaller.marshalTypeToOutputStream(sysmeta, out);
636
    }
637

    
638
    /**
639
     * Earthgrid API > Put Service >Put Function : calls MetacatHandler >
640
     * handleInsertOrUpdateAction
641
     * 
642
     * @param guid
643
     *            - ID of data object to be inserted or updated. If action is
644
     *            update, the pid is the existing pid. If insert, the pid is the
645
     *            new one
646
     * @throws InvalidRequest
647
     * @throws ServiceFailure
648
     * @throws IdentifierNotUnique
649
     * @throws JiBXException
650
     * @throws NotImplemented
651
     * @throws InvalidSystemMetadata
652
     * @throws InsufficientResources
653
     * @throws UnsupportedType
654
     * @throws NotAuthorized
655
     * @throws InvalidToken
656
     * @throws IOException
657
     * @throws IllegalAccessException
658
     * @throws InstantiationException
659
     */
660
    protected void putObject(String action) throws ServiceFailure,
661
            InvalidRequest, IdentifierNotUnique, JiBXException, InvalidToken,
662
            NotAuthorized, UnsupportedType, InsufficientResources,
663
            InvalidSystemMetadata, NotImplemented, IOException,
664
            InstantiationException, IllegalAccessException {
665
    	
666
        // Read the incoming data from its Mime Multipart encoding
667
        Map<String, File> files = collectMultipartFiles();
668
        
669
	    // get the encoded pid string from the body and make the object
670
        String pidString = multipartparams.get("pid").get(0);
671
        Identifier pid = new Identifier();
672
        pid.setValue(pidString);
673
        
674
        logMetacat.debug("putObject: " + pid.getValue() + "/" + action);
675
        
676
        InputStream object = null;
677
        InputStream sysmeta = null;
678

    
679
        File smFile = files.get("sysmeta");
680
        sysmeta = new FileInputStream(smFile);
681
        File objFile = files.get("object");
682
        object = new FileInputStream(objFile);
683

    
684
        if (action.equals(FUNCTION_NAME_INSERT)) { // handle inserts
685

    
686
            logMetacat.debug("Commence creation...");
687
            SystemMetadata smd = TypeMarshaller.unmarshalTypeFromStream(
688
                    SystemMetadata.class, sysmeta);
689

    
690
           
691
            logMetacat.debug("creating object with pid " + pid.getValue());
692
            Identifier rId = CNodeService.getInstance(request).create(session, pid, object, smd);
693

    
694
            OutputStream out = response.getOutputStream();
695
            response.setStatus(200);
696
            response.setContentType("text/xml");
697

    
698
            TypeMarshaller.marshalTypeToOutputStream(rId, out);
699

    
700
        } else {
701
            throw new InvalidRequest("1000", "Operation must be create.");
702
        }
703
    }
704

    
705
    /**
706
     * List the object formats registered with the system
707
     * 
708
     * @throws NotImplemented
709
     * @throws InsufficientResources
710
     * @throws NotFound
711
     * @throws ServiceFailure
712
     * @throws InvalidRequest
713
     * @throws IOException
714
     * @throws JiBXException
715
     */
716
    private void listFormats() throws InvalidRequest, ServiceFailure, NotFound,
717
            InsufficientResources, NotImplemented, IOException, JiBXException {
718
        logMetacat.debug("Entering listFormats()");
719

    
720
        ObjectFormatList objectFormatList = CNodeService.getInstance(request)
721
                .listFormats();
722
        // get the response output stream
723
        OutputStream out = response.getOutputStream();
724
        response.setStatus(200);
725
        response.setContentType("text/xml");
726

    
727
        // style the object with a processing directive
728
        String stylesheet = null;
729
        try {
730
            stylesheet = PropertyService.getProperty("dataone.types.xsl.v2");
731
        } catch (PropertyNotFoundException e) {
732
            logMetacat.warn("Could not locate DataONE types XSLT: "
733
                    + e.getMessage());
734
        }
735

    
736
        TypeMarshaller.marshalTypeToOutputStream(objectFormatList, out,
737
                stylesheet);
738

    
739
    }
740
    
741
    private void listChecksumAlgorithms() throws IOException, ServiceFailure,
742
			NotImplemented, JiBXException {
743
		logMetacat.debug("Entering listFormats()");
744

    
745
		ChecksumAlgorithmList result = CNodeService.getInstance(request).listChecksumAlgorithms();
746

    
747
		// get the response output stream
748
		OutputStream out = response.getOutputStream();
749
		response.setStatus(200);
750
		response.setContentType("text/xml");
751

    
752
		TypeMarshaller.marshalTypeToOutputStream(result, out);
753

    
754
	}
755
    
756
    /**
757
     * http://mule1.dataone.org/ArchitectureDocs-current/apis/CN_APIs.html#CNRead.describe
758
     * @param pid
759
     * @throws InvalidToken
760
     * @throws ServiceFailure
761
     * @throws NotAuthorized
762
     * @throws NotFound
763
     * @throws NotImplemented
764
     * @throws InvalidRequest
765
     */
766
    private void describeObject(String pid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, InvalidRequest
767
    {
768
        response.setContentType("text/xml");
769
        
770
        Identifier id = new Identifier();
771
        id.setValue(pid);
772
        
773
        DescribeResponse dr = null;
774
        try {
775
            dr = CNodeService.getInstance(request).describe(session, id);
776
        } catch (BaseException e) {
777
        	response.setStatus(e.getCode());
778
        	response.addHeader("DataONE-Exception-Name", e.getClass().getName());
779
            response.addHeader("DataONE-Exception-DetailCode", e.getDetail_code());
780
            response.addHeader("DataONE-Exception-Description", e.getDescription());
781
            response.addHeader("DataONE-Exception-PID", id.getValue());
782
            return;
783
		}
784
        
785
        response.setStatus(200);
786
        //response.addHeader("pid", pid);
787
        response.addHeader("DataONE-Checksum", dr.getDataONE_Checksum().getAlgorithm() + "," + dr.getDataONE_Checksum().getValue());
788
        response.addHeader("Content-Length", dr.getContent_Length() + "");
789
        response.addHeader("Last-Modified", DateTimeMarshaller.serializeDateToUTC(dr.getLast_Modified()));
790
        response.addHeader("DataONE-ObjectFormat", dr.getDataONE_ObjectFormatIdentifier().getValue());
791
        response.addHeader("DataONE-SerialVersion", dr.getSerialVersion().toString());
792

    
793
    }
794
    
795
    /**
796
     * Handle delete 
797
     * @param pid ID of data object to be deleted
798
     * @throws IOException
799
     * @throws InvalidRequest 
800
     * @throws NotImplemented 
801
     * @throws NotFound 
802
     * @throws NotAuthorized 
803
     * @throws ServiceFailure 
804
     * @throws InvalidToken 
805
     * @throws JiBXException 
806
     */
807
    private void deleteObject(String pid) throws IOException, InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, InvalidRequest, JiBXException 
808
    {
809

    
810
        OutputStream out = response.getOutputStream();
811
        response.setStatus(200);
812
        response.setContentType("text/xml");
813

    
814
        Identifier id = new Identifier();
815
        id.setValue(pid);
816

    
817
        logMetacat.debug("Calling delete for identifier " + pid);
818
        CNodeService.getInstance(request).delete(session, id);
819
        TypeMarshaller.marshalTypeToOutputStream(id, out);
820
        
821
    }
822
    
823
    /**
824
     * Archives the given pid
825
     * @param pid
826
     * @throws InvalidToken
827
     * @throws ServiceFailure
828
     * @throws NotAuthorized
829
     * @throws NotFound
830
     * @throws NotImplemented
831
     * @throws IOException
832
     * @throws JiBXException
833
     */
834
    private void archive(String pid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, IOException, JiBXException {
835

    
836
        OutputStream out = response.getOutputStream();
837
        response.setStatus(200);
838
        response.setContentType("text/xml");
839

    
840
        Identifier id = new Identifier();
841
        id.setValue(pid);
842

    
843
        logMetacat.debug("Calling archive");
844
        CNodeService.getInstance(request).archive(session, id);
845
        
846
        TypeMarshaller.marshalTypeToOutputStream(id, out);
847
        
848
    }
849

    
850
    /**
851
     * Return the requested object format
852
     * 
853
     * @param fmtidStr
854
     *            the requested format identifier as a string
855
     * @throws NotImplemented
856
     * @throws InsufficientResources
857
     * @throws NotFound
858
     * @throws ServiceFailure
859
     * @throws InvalidRequest
860
     * @throws IOException
861
     * @throws JiBXException
862
     */
863
    private void getFormat(String fmtidStr) throws InvalidRequest,
864
            ServiceFailure, NotFound, InsufficientResources, NotImplemented,
865
            IOException, JiBXException {
866
        logMetacat.debug("Entering listFormats()");
867

    
868
        ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
869
        fmtid.setValue(fmtidStr);
870

    
871
        // get the specified object format
872
        ObjectFormat objectFormat = CNodeService.getInstance(request)
873
                .getFormat(fmtid);
874

    
875
        OutputStream out = response.getOutputStream();
876
        response.setStatus(200);
877
        response.setContentType("text/xml");
878

    
879
        TypeMarshaller.marshalTypeToOutputStream(objectFormat, out);
880

    
881
    }
882

    
883
    /**
884
     * Adds a new {@link ObjectFormat} to the object format list.
885
     * 
886
     * @param formatIdStr the format identifier
887
     * 
888
     * @throws NotImplemented 
889
     * @throws InvalidRequest 
890
     * @throws ServiceFailure 
891
     * @throws JiBXException 
892
     * @throws IOException 
893
     * @throws IllegalAccessException 
894
     * @throws InstantiationException 
895
     * @throws NotFound 
896
     * @throws NotAuthorized 
897
     * @throws InvalidToken 
898
     */
899
    private void addFormat(String formatIdStr) 
900
            throws NotImplemented, ServiceFailure, InvalidRequest, InstantiationException, 
901
            IllegalAccessException, IOException, JiBXException, NotFound, NotAuthorized, InvalidToken {
902
        
903
        logMetacat.debug("addFormat: " + formatIdStr);
904
        
905
        Map<String, File> files = collectMultipartFiles();
906
        File formatFile = files.get("format");
907
        FileInputStream formatStream = new FileInputStream(formatFile);
908
        ObjectFormat objectFormat = TypeMarshaller.unmarshalTypeFromStream(ObjectFormat.class, formatStream);
909
        ObjectFormatIdentifier formatId = new ObjectFormatIdentifier();
910
        formatId.setValue(formatIdStr);
911
        
912
        ObjectFormatIdentifier formatID = CNodeService.getInstance(request).addFormat(session, formatId, objectFormat);
913
        
914
        OutputStream out = response.getOutputStream();
915
        response.setStatus(200);
916
        response.setContentType("text/xml");
917
        TypeMarshaller.marshalTypeToOutputStream(formatID, out);
918
    }
919
    
920
    /**
921
     * Reserve the given Identifier
922
     * 
923
     * @throws InvalidToken
924
     * @throws ServiceFailure
925
     * @throws NotAuthorized
926
     * @throws IdentifierNotUnique
927
     * @throws NotImplemented
928
     * @throws InvalidRequest
929
     */
930
    private void reserve() 
931
        throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique, 
932
        NotImplemented, InvalidRequest {
933
        Identifier pid = null;
934
        String scope = null;
935
        String format = null;
936

    
937
        // Parse the params out of the multipart form data
938
        logMetacat.debug("Parsing reserve parameters from the mime multipart entity");
939
        try {
940
            collectMultipartParams();
941
            
942
        } catch (FileUploadException e1) {
943
            String msg = "FileUploadException: Couldn't parse the mime multipart information: " +
944
            e1.getMessage();
945
            logMetacat.debug(msg);
946
            throw new ServiceFailure("4210", msg);
947

    
948
        } catch (IOException e1) {
949
            String msg = "IOException: Couldn't parse the mime multipart information: " +
950
            e1.getMessage();
951
            logMetacat.debug(msg);
952
            throw new ServiceFailure("4210", msg);
953
        
954
        } catch (Exception e1) {
955
            String msg = "Exception: Couldn't parse the mime multipart information: " +
956
            e1.getMessage();
957
            logMetacat.debug(msg);
958
            throw new ServiceFailure("4210", msg);
959

    
960
        }
961
        
962
        // gather the params
963
        try {
964
            String id = multipartparams.get("pid").get(0);
965
            pid = new Identifier();
966
            pid.setValue(id);
967
            
968
        } catch (NullPointerException e) {
969
            String msg = "The 'pid' must be provided as a parameter and was not.";
970
            logMetacat.error(msg);
971
            throw new InvalidRequest("4200", msg);
972
 
973
        }
974
        
975
        // call the implementation
976
        try {
977
            Identifier resultPid = CNodeService.getInstance(request).reserveIdentifier(session, pid);
978
            OutputStream out = response.getOutputStream();
979
            response.setStatus(200);
980
            response.setContentType("text/xml");
981
            // send back the reserved pid
982
            TypeMarshaller.marshalTypeToOutputStream(resultPid, out);
983
            
984
        } catch (IOException e) {
985
            String msg = "Couldn't write the identifier to the response output stream: " +
986
                e.getMessage();
987
            logMetacat.debug(msg);
988
            throw new ServiceFailure("4210", msg);
989
        
990
        } catch (JiBXException e) {
991
            String msg = "Couldn't marshall the identifier to the response output stream: " +
992
            e.getMessage();
993
            logMetacat.debug(msg);
994
            throw new ServiceFailure("4210", msg);
995
            
996
        }
997
    }
998

    
999
    /**
1000
     * 
1001
     * @param id
1002
     * @throws InvalidRequest
1003
     * @throws InvalidToken
1004
     * @throws ServiceFailure
1005
     * @throws NotAuthorized
1006
     * @throws NotFound
1007
     * @throws NotImplemented
1008
     * @throws IOException
1009
     * @throws JiBXException
1010
     */
1011
    private void resolve(String id) throws InvalidRequest, InvalidToken,
1012
            ServiceFailure, NotAuthorized, NotFound, NotImplemented,
1013
            IOException, JiBXException {
1014
        Identifier pid = new Identifier();
1015
        pid.setValue(id);
1016
        ObjectLocationList locationList = CNodeService.getInstance(request)
1017
                .resolve(session, pid);
1018
        OutputStream out = response.getOutputStream();
1019
        response.setStatus(200);
1020
        response.setContentType("text/xml");
1021
        TypeMarshaller.marshalTypeToOutputStream(locationList, out);
1022

    
1023
    }
1024

    
1025
    /**
1026
     * Set the owner of a resource
1027
     * 
1028
     * @param id
1029
     * @throws InvalidToken
1030
     * @throws ServiceFailure
1031
     * @throws NotFound
1032
     * @throws NotAuthorized
1033
     * @throws NotImplemented
1034
     * @throws InvalidRequest
1035
     * @throws IllegalAccessException
1036
     * @throws InstantiationException
1037
     * @throws VersionMismatch 
1038
     */
1039
    private void owner(String id) 
1040
        throws InvalidToken, ServiceFailure, NotFound, NotAuthorized, 
1041
        NotImplemented, InvalidRequest, InstantiationException, 
1042
        IllegalAccessException, VersionMismatch {
1043

    
1044
        Identifier pid = new Identifier();
1045
        pid.setValue(id);
1046

    
1047
        long serialVersion = 0L;
1048
        String serialVersionStr = null;
1049
        String userIdStr = null;
1050
        Subject userId = null;
1051
        
1052
        // Parse the params out of the multipart form data
1053
        // Read the incoming data from its Mime Multipart encoding
1054
        logMetacat.debug("Parsing rights holder parameters from the mime multipart entity");
1055
        try {
1056
            collectMultipartParams();
1057
            
1058
        } catch (FileUploadException e1) {
1059
            String msg = "FileUploadException: Couldn't parse the mime multipart information: " +
1060
            e1.getMessage();
1061
            logMetacat.debug(msg);
1062
            throw new ServiceFailure("4490", msg);
1063

    
1064
        } catch (IOException e1) {
1065
            String msg = "IOException: Couldn't parse the mime multipart information: " +
1066
            e1.getMessage();
1067
            logMetacat.debug(msg);
1068
            throw new ServiceFailure("4490", msg);
1069
        
1070
        } catch (Exception e1) {
1071
            String msg = "Exception: Couldn't parse the mime multipart information: " +
1072
            e1.getMessage();
1073
            logMetacat.debug(msg);
1074
            throw new ServiceFailure("4490", msg);
1075

    
1076
        }
1077
        
1078
        // get the serialVersion
1079
        try {
1080
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1081
            serialVersion = new Long(serialVersionStr).longValue();
1082
            
1083
        } catch (NumberFormatException nfe) {
1084
            String msg = "The 'serialVersion' must be provided as a positive integer and was not.";
1085
            logMetacat.error(msg);
1086
            throw new InvalidRequest("4442", msg);
1087
                        
1088
        } catch (NullPointerException e) {
1089
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1090
            logMetacat.error(msg);
1091
            throw new InvalidRequest("4442", msg);
1092
            
1093
        }
1094

    
1095
        // get the subject userId that will become the rights holder
1096
        try {
1097
            userIdStr = multipartparams.get("userId").get(0);
1098
            userId = new Subject();
1099
            userId.setValue(userIdStr);
1100
                                    
1101
        } catch (NullPointerException e) {
1102
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1103
            logMetacat.error(msg);
1104
            throw new InvalidRequest("4442", msg);
1105
            
1106
        }
1107

    
1108
        // set the rights holder
1109
        Identifier retPid = CNodeService.getInstance(request).setRightsHolder(session, pid, userId, serialVersion);
1110
        
1111
        try {
1112
            OutputStream out = response.getOutputStream();
1113
            response.setStatus(200);
1114
            response.setContentType("text/xml");
1115
            TypeMarshaller.marshalTypeToOutputStream(retPid, out);
1116
            
1117
        } catch (IOException e) {
1118
            String msg = "Couldn't write the identifier to the response output stream: " +
1119
                e.getMessage();
1120
            logMetacat.debug(msg);
1121
            throw new ServiceFailure("4490", msg);
1122
        
1123
        } catch (JiBXException e) {
1124
            String msg = "Couldn't marshall the identifier to the response output stream: " +
1125
            e.getMessage();
1126
            logMetacat.debug(msg);
1127
            throw new ServiceFailure("4490", msg);
1128
            
1129
        }
1130
    }
1131

    
1132
    /**
1133
     * Processes the authorization check for given id
1134
     * 
1135
     * @param id
1136
     * @return
1137
     * @throws ServiceFailure
1138
     * @throws InvalidToken
1139
     * @throws NotFound
1140
     * @throws NotAuthorized
1141
     * @throws NotImplemented
1142
     * @throws InvalidRequest
1143
     */
1144
    private boolean isAuthorized(String id) throws ServiceFailure,
1145
            InvalidToken, NotFound, NotAuthorized, NotImplemented,
1146
            InvalidRequest {
1147
        Identifier pid = new Identifier();
1148
        pid.setValue(id);
1149
        String permission = params.get("action")[0];
1150
        boolean result = CNodeService.getInstance(request).isAuthorized(
1151
                session, pid, Permission.convert(permission));
1152
        response.setStatus(200);
1153
        response.setContentType("text/xml");
1154
        return result;
1155
    }
1156

    
1157
    /**
1158
     * Register System Metadata without data or metadata object
1159
     * 
1160
     * @param pid
1161
     *            identifier for System Metadata entry
1162
     * @throws JiBXException
1163
     * @throws FileUploadException
1164
     * @throws IOException
1165
     * @throws InvalidRequest
1166
     * @throws ServiceFailure
1167
     * @throws InvalidSystemMetadata
1168
     * @throws NotAuthorized
1169
     * @throws NotImplemented
1170
     * @throws IllegalAccessException
1171
     * @throws InstantiationException
1172
     */
1173
    protected void registerSystemMetadata()
1174
            throws ServiceFailure, InvalidRequest, IOException,
1175
            FileUploadException, JiBXException, NotImplemented, NotAuthorized,
1176
            InvalidSystemMetadata, InstantiationException,
1177
            IllegalAccessException {
1178
    	
1179
    	// Read the incoming data from its Mime Multipart encoding
1180
        Map<String, File> files = collectMultipartFiles();
1181
        
1182
    	// get the encoded pid string from the body and make the object
1183
        String pidString = multipartparams.get("pid").get(0);
1184
        Identifier pid = new Identifier();
1185
        pid.setValue(pidString);
1186
        
1187
        logMetacat.debug("registerSystemMetadata: " + pid);
1188

    
1189
        // get the system metadata from the request
1190
        File smFile = files.get("sysmeta");
1191
        FileInputStream sysmeta = new FileInputStream(smFile);
1192
        SystemMetadata systemMetadata = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysmeta);
1193

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

    
1197
        OutputStream out = response.getOutputStream();
1198
        response.setStatus(200);
1199
        response.setContentType("text/xml");
1200
        
1201
        TypeMarshaller.marshalTypeToOutputStream(retGuid, out);
1202

    
1203
    }
1204

    
1205
    /**
1206
     * set the access perms on a document
1207
     * 
1208
     * @throws JiBXException
1209
     * @throws InvalidRequest
1210
     * @throws NotImplemented
1211
     * @throws NotAuthorized
1212
     * @throws NotFound
1213
     * @throws ServiceFailure
1214
     * @throws InvalidToken
1215
     * @throws IllegalAccessException
1216
     * @throws InstantiationException
1217
     * @throws IOException
1218
     * @throws SAXException
1219
     * @throws ParserConfigurationException
1220
     * @throws VersionMismatch 
1221
     */
1222
    protected void setAccess(String pid) throws JiBXException, InvalidToken,
1223
            ServiceFailure, NotFound, NotAuthorized, NotImplemented,
1224
            InvalidRequest, IOException, InstantiationException,
1225
            IllegalAccessException, ParserConfigurationException, SAXException, VersionMismatch {
1226

    
1227
        long serialVersion = 0L;
1228
        String serialVersionStr = null;
1229
        
1230
        // parse the accessPolicy
1231
        Map<String, File> files = collectMultipartFiles();        
1232
        AccessPolicy accessPolicy = TypeMarshaller.unmarshalTypeFromFile(AccessPolicy.class, files.get("accessPolicy"));;
1233

    
1234
        // get the serialVersion
1235
        try {
1236
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1237
            serialVersion = new Long(serialVersionStr).longValue();
1238

    
1239
        } catch (NumberFormatException nfe) {
1240
            String msg = "The 'serialVersion' must be provided as a positive integer and was not.";
1241
            logMetacat.error(msg);
1242
            throw new InvalidRequest("4402", msg);
1243
            
1244
        } catch (NullPointerException e) {
1245
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1246
            logMetacat.error(msg);
1247
            throw new InvalidRequest("4402", msg);
1248

    
1249
        }
1250

    
1251
        Identifier id = new Identifier();
1252
        id.setValue(pid);
1253

    
1254
        CNodeService.getInstance(request).setAccessPolicy(session, id,
1255
                accessPolicy, serialVersion);
1256

    
1257
    }
1258

    
1259
    /**
1260
     * List the objects
1261
     * 
1262
     * @throws NotImplemented
1263
     * @throws InvalidRequest
1264
     * @throws NotAuthorized
1265
     * @throws ServiceFailure
1266
     * @throws InvalidToken
1267
     * @throws NotFound
1268
     * @throws IOException
1269
     * @throws JiBXException
1270
     * @throws Exception
1271
     */
1272
    private void listObjects() throws InvalidToken, ServiceFailure,
1273
            NotAuthorized, InvalidRequest, NotImplemented, NotFound,
1274
            IOException, JiBXException {
1275

    
1276
        Date startTime = null;
1277
        Date endTime = null;
1278
        ObjectFormatIdentifier formatId = null;
1279
        Identifier identifier = null;
1280
        boolean replicaStatus = true;
1281
        int start = 0;
1282
        int count = 1000;
1283
        Enumeration<String> paramlist = request.getParameterNames();
1284
        while (paramlist.hasMoreElements()) {
1285
            // parse the params and make the call
1286
            String name = paramlist.nextElement();
1287
            String[] values = request.getParameterValues(name);
1288
            String value = null;
1289
            if (values != null && values.length > 0) {
1290
            	value = values[0];
1291
            	value = EncodingUtilities.decodeString(value);
1292
            }
1293

    
1294
            if (name.equals("fromDate") && value != null) {
1295
                try {
1296
                    startTime = DateTimeMarshaller.deserializeDateToUTC(value);
1297
                } catch (Exception e) {
1298
                    // if we can't parse it, just don't use the startTime param
1299
                    logMetacat.warn("Could not parse fromDate: " + value);
1300
                    startTime = null;
1301
                }
1302
            } else if (name.equals("toDate") && value != null) {
1303
                try {
1304
                    endTime = DateTimeMarshaller.deserializeDateToUTC(value);
1305
                } catch (Exception e) {
1306
                    // if we can't parse it, just don't use the endTime param
1307
                    logMetacat.warn("Could not parse toDate: " + value);
1308
                    endTime = null;
1309
                }
1310
            } else if (name.equals("formatId") && value != null) {
1311
            	formatId = new ObjectFormatIdentifier();
1312
            	formatId.setValue(value);
1313
            } else if (name.equals("identifier") && value != null) {
1314
            	identifier = new Identifier();
1315
            	identifier.setValue(value);
1316
            } else if (name.equals("replicaStatus") && value != null) {
1317
                replicaStatus = Boolean.parseBoolean(value);
1318
            } else if (name.equals("start") && value != null) {
1319
                start = Integer.valueOf(value);
1320
            } else if (name.equals("count") && value != null) {
1321
                count = Integer.valueOf(value);
1322
            }
1323
        }
1324
        // make the call
1325
        logMetacat.debug("session: " + session + " fromDate: " + startTime
1326
                + " toDate: " + endTime + " formatId: " + formatId
1327
                + " replicaStatus: " + replicaStatus + " start: " + start
1328
                + " count: " + count);        
1329

    
1330
        // get the list
1331
        ObjectList ol = CNodeService.getInstance(request).listObjects(session,
1332
                startTime, endTime, formatId, identifier, replicaStatus, start, count);
1333

    
1334
        // send it
1335
        OutputStream out = response.getOutputStream();
1336
        response.setStatus(200);
1337
        response.setContentType("text/xml");
1338

    
1339
        // style the object with a processing directive
1340
        String stylesheet = null;
1341
        try {
1342
            stylesheet = PropertyService.getProperty("dataone.types.xsl.v2");
1343
        } catch (PropertyNotFoundException e) {
1344
            logMetacat.warn("Could not locate DataONE types XSLT: "
1345
                    + e.getMessage());
1346
        }
1347

    
1348
        // Serialize and write it to the output stream
1349
        TypeMarshaller.marshalTypeToOutputStream(ol, out, stylesheet);
1350
    }
1351

    
1352
    /**
1353
     * Pass the request to get node replication authorization to CNodeService
1354
     * 
1355
     * @param pid
1356
     *            the identifier of the object to get authorization to replicate
1357
     * 
1358
     * @throws NotImplemented
1359
     * @throws NotAuthorized
1360
     * @throws InvalidToken
1361
     * @throws ServiceFailure
1362
     * @throws NotFound
1363
     * @throws InvalidRequest
1364
     */
1365
    public boolean isNodeAuthorized(String pid) throws NotImplemented,
1366
            NotAuthorized, InvalidToken, ServiceFailure, NotFound,
1367
            InvalidRequest {
1368

    
1369
        boolean result = false;
1370
        Subject targetNodeSubject = new Subject();
1371
        String nodeSubject = null;
1372
        String replPermission = null;
1373

    
1374
        // get the pid
1375
        Identifier identifier = new Identifier();
1376
        identifier.setValue(pid);
1377

    
1378
        // get the target node subject
1379
        try {
1380
            nodeSubject = params.get("targetNodeSubject")[0];
1381
            targetNodeSubject.setValue(nodeSubject);
1382

    
1383
        } catch (NullPointerException e) {
1384
            String msg = "The 'targetNodeSubject' must be provided as a parameter and was not.";
1385
            logMetacat.error(msg);
1386
            throw new InvalidRequest("4873", msg);
1387

    
1388
        }
1389

    
1390
        result = CNodeService.getInstance(request).isNodeAuthorized(session, targetNodeSubject, identifier);
1391

    
1392
        response.setStatus(200);
1393
        response.setContentType("text/xml");
1394
        return result;
1395

    
1396
    }
1397

    
1398
    /**
1399
     * Pass the request to set the replication policy to CNodeService
1400
     * 
1401
     * @param pid
1402
     *            the identifier of the object to set the replication policy on
1403
     * 
1404
     * @throws NotImplemented
1405
     * @throws NotFound
1406
     * @throws NotAuthorized
1407
     * @throws ServiceFailure
1408
     * @throws InvalidRequest
1409
     * @throws InvalidToken
1410
     * @throws IOException
1411
     * @throws InstantiationException
1412
     * @throws IllegalAccessException
1413
     * @throws JiBXException
1414
     * @throws VersionMismatch 
1415
     */
1416
    public boolean setReplicationPolicy(String pid) throws NotImplemented,
1417
            NotFound, NotAuthorized, ServiceFailure, InvalidRequest,
1418
            InvalidToken, IOException, InstantiationException,
1419
            IllegalAccessException, JiBXException, VersionMismatch {
1420

    
1421
        boolean result = false;
1422
        long serialVersion = 0L;
1423
        String serialVersionStr = null;
1424

    
1425
        Identifier identifier = new Identifier();
1426
        identifier.setValue(pid);
1427

    
1428
        // parse the policy
1429
        Map<String, File> files = collectMultipartFiles();        
1430
        ReplicationPolicy policy = TypeMarshaller.unmarshalTypeFromFile(ReplicationPolicy.class, files.get("policy"));
1431

    
1432
        // get the serialVersion
1433
        try {
1434
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1435
            serialVersion = new Long(serialVersionStr).longValue();
1436

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

    
1442
        }
1443
        result = CNodeService.getInstance(request).setReplicationPolicy(
1444
                session, identifier, policy, serialVersion);
1445
        response.setStatus(200);
1446
        response.setContentType("text/xml");
1447
        return result;
1448

    
1449
    }
1450
    
1451
    /**
1452
     * Update the system metadata for a given pid, setting it to be obsoleted
1453
     * by the obsoletedByPid
1454
     *  
1455
     * @param pid
1456
     * @return
1457
     * @throws NotImplemented
1458
     * @throws NotFound
1459
     * @throws NotAuthorized
1460
     * @throws ServiceFailure
1461
     * @throws InvalidRequest
1462
     * @throws InvalidToken
1463
     * @throws InstantiationException
1464
     * @throws IllegalAccessException
1465
     * @throws VersionMismatch
1466
     */
1467
    public boolean setObsoletedBy(String pid) 
1468
        throws NotImplemented, NotFound, NotAuthorized, ServiceFailure, 
1469
        InvalidRequest, InvalidToken, InstantiationException, 
1470
        IllegalAccessException, VersionMismatch {
1471

    
1472
        boolean result = false;
1473
        long serialVersion = 0L;
1474
        String serialVersionStr = null;
1475

    
1476
        Identifier identifier = new Identifier();
1477
        identifier.setValue(pid);
1478
        String obsoletedByPidString = null;
1479
        Identifier obsoletedByPid = null;
1480

    
1481
        // Parse the params out of the multipart form data
1482
        // Read the incoming data from its Mime Multipart encoding
1483
        logMetacat.debug("Parsing rights holder parameters from the mime multipart entity");
1484
        try {
1485
            collectMultipartParams();
1486
            
1487
        } catch (FileUploadException e1) {
1488
            String msg = "FileUploadException: Couldn't parse the mime multipart information: " +
1489
            e1.getMessage();
1490
            logMetacat.debug(msg);
1491
            throw new ServiceFailure("4941", msg);
1492

    
1493
        } catch (IOException e1) {
1494
            String msg = "IOException: Couldn't parse the mime multipart information: " +
1495
            e1.getMessage();
1496
            logMetacat.debug(msg);
1497
            throw new ServiceFailure("4941", msg);
1498
        
1499
        } catch (Exception e1) {
1500
            String msg = "Exception: Couldn't parse the mime multipart information: " +
1501
            e1.getMessage();
1502
            logMetacat.debug(msg);
1503
            throw new ServiceFailure("4941", msg);
1504

    
1505
        }
1506

    
1507
        // get the obsoletedByPid
1508
        try {
1509
            obsoletedByPidString = multipartparams.get("obsoletedByPid").get(0);
1510
            obsoletedByPid = new Identifier();
1511
            obsoletedByPid.setValue(obsoletedByPidString);
1512
        } catch (NullPointerException e) {
1513
            String msg = "The 'obsoletedByPid' must be provided as a parameter and was not.";
1514
            logMetacat.error(msg);
1515
            throw new InvalidRequest("4883", msg);
1516
        }
1517

    
1518
        // get the serialVersion
1519
        try {
1520
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1521
            serialVersion = new Long(serialVersionStr).longValue();
1522
            
1523
        } catch (NumberFormatException nfe) {
1524
            String msg = "The 'serialVersion' must be provided as a positive integer and was not.";
1525
            logMetacat.error(msg);
1526
            throw new InvalidRequest("4942", msg);
1527
                        
1528
        } catch (NullPointerException e) {
1529
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1530
            logMetacat.error(msg);
1531
            throw new InvalidRequest("4942", msg);
1532
            
1533
        }
1534
        result = CNodeService.getInstance(request).setObsoletedBy(session,
1535
            identifier, obsoletedByPid, serialVersion);
1536
        response.setStatus(200);
1537
        response.setContentType("text/xml");
1538
        return result;
1539

    
1540
    }
1541
    
1542
    /**
1543
     * Delete the replica entry with the given nodeId for the given pid
1544
     * 
1545
     * @param pid
1546
     * @return
1547
     * @throws NotImplemented
1548
     * @throws NotFound
1549
     * @throws NotAuthorized
1550
     * @throws ServiceFailure
1551
     * @throws InvalidRequest
1552
     * @throws InvalidToken
1553
     * @throws InstantiationException
1554
     * @throws IllegalAccessException
1555
     * @throws VersionMismatch
1556
     */
1557
    public boolean deleteReplica(String pid) 
1558
        throws NotImplemented, NotFound, NotAuthorized, ServiceFailure, 
1559
        InvalidRequest, InvalidToken, InstantiationException, 
1560
        IllegalAccessException, VersionMismatch {
1561

    
1562
        boolean result = false;
1563
        long serialVersion = 0L;
1564
        String serialVersionStr = null;
1565

    
1566
        Identifier identifier = new Identifier();
1567
        identifier.setValue(pid);
1568

    
1569
        NodeReference nodeId = null;
1570
        
1571
        // Parse the params out of the multipart form data
1572
        // Read the incoming data from its Mime Multipart encoding
1573
        logMetacat.debug("Parsing delete replica parameters from the mime multipart entity");
1574
        try {
1575
            collectMultipartParams();
1576
            
1577
        } catch (FileUploadException e1) {
1578
            String msg = "FileUploadException: Couldn't parse the mime multipart information: " +
1579
            e1.getMessage();
1580
            logMetacat.debug(msg);
1581
            throw new ServiceFailure("4951", msg);
1582

    
1583
        } catch (IOException e1) {
1584
            String msg = "IOException: Couldn't parse the mime multipart information: " +
1585
            e1.getMessage();
1586
            logMetacat.debug(msg);
1587
            throw new ServiceFailure("4951", msg);
1588
        
1589
        } catch (Exception e1) {
1590
            String msg = "Exception: Couldn't parse the mime multipart information: " +
1591
            e1.getMessage();
1592
            logMetacat.debug(msg);
1593
            throw new ServiceFailure("4951", msg);
1594

    
1595
        }
1596
        
1597
        // get the nodeId param
1598
        try {
1599
            String nodeIdString = multipartparams.get("nodeId").get(0);
1600
            nodeId = new NodeReference();
1601
            nodeId.setValue(nodeIdString);
1602
            
1603
        } catch (NullPointerException e) {
1604
            String msg = "The 'nodeId' must be provided as a parameter and was not.";
1605
            logMetacat.error(msg);
1606
            throw new InvalidRequest("4952", msg);
1607
        }
1608

    
1609
        // get the serialVersion
1610
        try {
1611
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1612
            serialVersion = new Long(serialVersionStr).longValue();
1613
            
1614
        } catch (NumberFormatException nfe) {
1615
            String msg = "The 'serialVersion' must be provided as a positive integer and was not.";
1616
            logMetacat.error(msg);
1617
            throw new InvalidRequest("4952", msg);
1618
                        
1619
        } catch (NullPointerException e) {
1620
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1621
            logMetacat.error(msg);
1622
            throw new InvalidRequest("4952", msg);
1623
            
1624
        }
1625
        result = CNodeService.getInstance(request).deleteReplicationMetadata(
1626
                session, identifier, nodeId, serialVersion);
1627
        response.setStatus(200);
1628
        response.setContentType("text/xml");
1629
        return result;
1630

    
1631
    }
1632

    
1633
    /**
1634
     * Pass the request to set the replication status to CNodeService
1635
     * 
1636
     * @param pid
1637
     *            the identifier of the object to set the replication status on
1638
     * 
1639
     * @throws ServiceFailure
1640
     * @throws NotImplemented
1641
     * @throws InvalidToken
1642
     * @throws NotAuthorized
1643
     * @throws InvalidRequest
1644
     * @throws NotFound
1645
     * @throws JiBXException 
1646
     * @throws IllegalAccessException 
1647
     * @throws InstantiationException 
1648
     * @throws IOException 
1649
     */
1650
    public boolean setReplicationStatus(String pid) throws ServiceFailure,
1651
            NotImplemented, InvalidToken, NotAuthorized, InvalidRequest,
1652
            NotFound {
1653
        
1654
        boolean result = false;
1655
        Identifier identifier = new Identifier();
1656
        identifier.setValue(pid);
1657
        BaseException failure = null;
1658
        ReplicationStatus status = null;
1659
        String replicationStatus = null;
1660
        NodeReference targetNodeRef = null;
1661
        String targetNode = null;
1662

    
1663
        // Parse the params out of the multipart form data
1664
        // Read the incoming data from its Mime Multipart encoding
1665
        logMetacat.debug("Parsing ReplicaStatus from the mime multipart entity");
1666

    
1667
        try {
1668
        	// parse the policy
1669
            Map<String, File> files = collectMultipartFiles();        
1670
            failure = ExceptionHandler.deserializeXml(new FileInputStream(files.get("failure")), 
1671
                    "Replication failed for an unknown reason.");
1672
            
1673
        } catch (Exception e2) {
1674
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1675
                e2.getMessage());
1676
            
1677
        }
1678
        
1679
        // get the replication status param
1680
        try {
1681
            replicationStatus = multipartparams.get("status").get(0);
1682
            status = ReplicationStatus.convert(replicationStatus);
1683

    
1684
        } catch (NullPointerException npe) {
1685

    
1686
            logMetacat.debug("The 'status' parameter was not found in the "
1687
                    + "multipartparams map.  Trying the params map.");
1688

    
1689
            try {
1690
                replicationStatus = params.get("status")[0];
1691
                status = ReplicationStatus.convert(replicationStatus
1692
                        .toLowerCase());
1693

    
1694
            } catch (Exception e) {
1695
                String msg = "The 'status' must be provided as a parameter and was not.";
1696
                logMetacat.error(msg);
1697
                throw new InvalidRequest("4730", msg);
1698

    
1699
            }
1700

    
1701
        }
1702

    
1703
        // get the target node reference param
1704
        try {
1705
            targetNode = multipartparams.get("nodeRef").get(0);
1706
            targetNodeRef = new NodeReference();
1707
            targetNodeRef.setValue(targetNode);
1708

    
1709
        } catch (NullPointerException e) {
1710
            logMetacat.debug("The 'nodeRef' parameter was not found in the "
1711
                    + "multipartparams map.  Trying the params map.");
1712

    
1713
            try {
1714
                targetNode = params.get("nodeRef")[0];
1715
                targetNodeRef = new NodeReference();
1716
                targetNodeRef.setValue(targetNode);
1717

    
1718
            } catch (Exception e1) {
1719
                String msg = "The 'nodeRef' must be provided as a parameter and was not.";
1720
                logMetacat.error(msg);
1721
                throw new InvalidRequest("4730", msg);
1722

    
1723
            }
1724

    
1725
        }
1726

    
1727
        result = CNodeService.getInstance(request).setReplicationStatus(
1728
                session, identifier, targetNodeRef, status, failure);
1729
        response.setStatus(200);
1730
        response.setContentType("text/xml");
1731
        return result;
1732

    
1733
    }
1734

    
1735
    /**
1736
     * Pass the request to update the replication metadata to CNodeService
1737
     * 
1738
     * @param pid
1739
     *            the identifier of the object to update the replication
1740
     *            metadata on
1741
     * 
1742
     * @throws ServiceFailure
1743
     * @throws NotImplemented
1744
     * @throws InvalidToken
1745
     * @throws NotAuthorized
1746
     * @throws InvalidRequest
1747
     * @throws NotFound
1748
     * @throws VersionMismatch 
1749
     * @throws JiBXException 
1750
     * @throws IOException 
1751
     * @throws IllegalAccessException 
1752
     * @throws InstantiationException 
1753
     */
1754
    public boolean updateReplicationMetadata(String pid) throws ServiceFailure,
1755
            NotImplemented, InvalidToken, NotAuthorized, InvalidRequest,
1756
            NotFound, VersionMismatch, InstantiationException, IllegalAccessException, IOException, JiBXException {
1757

    
1758
        boolean result = false;
1759
        long serialVersion = 0L;
1760
        String serialVersionStr = null;
1761
        Identifier identifier = new Identifier();
1762
        identifier.setValue(pid);
1763

    
1764
        // parse the replica
1765
        Map<String, File> files = collectMultipartFiles();        
1766
        Replica replica = TypeMarshaller.unmarshalTypeFromFile(Replica.class, files.get("replicaMetadata"));
1767

    
1768
        // get the serialVersion
1769
        try {
1770
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1771
            serialVersion = new Long(serialVersionStr).longValue();
1772

    
1773
        } catch (NullPointerException e) {
1774
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1775
            logMetacat.error(msg);
1776
            throw new InvalidRequest("4853", msg);
1777

    
1778
        }
1779

    
1780
        result = CNodeService.getInstance(request).updateReplicationMetadata(
1781
                session, identifier, replica, serialVersion);
1782
        response.setStatus(200);
1783
        response.setContentType("text/xml");
1784
        return result;
1785

    
1786
    }
1787
    
1788
    /**
1789
     * Update the system metadata for a specified pid
1790
     * @throws ServiceFailure
1791
     * @throws InvalidRequest
1792
     * @throws InstantiationException
1793
     * @throws IllegalAccessException
1794
     * @throws IOException
1795
     * @throws JiBXException
1796
     * @throws NotImplemented
1797
     * @throws NotAuthorized
1798
     * @throws InvalidSystemMetadata
1799
     * @throws InvalidToken
1800
     */
1801
    protected void updateSystemMetadata() throws ServiceFailure, InvalidRequest, InstantiationException, 
1802
                        IllegalAccessException, IOException, JiBXException, NotImplemented, NotAuthorized, InvalidSystemMetadata, InvalidToken {
1803
        // Read the incoming data from its Mime Multipart encoding
1804
        Map<String, File> files = collectMultipartFiles();
1805
        
1806
        // get the encoded pid string from the body and make the object
1807
        String pidString = multipartparams.get("pid").get(0);
1808
        Identifier pid = new Identifier();
1809
        pid.setValue(pidString);
1810
        
1811
        logMetacat.debug("updateSystemMetadata: " + pid);
1812

    
1813
        // get the system metadata from the request
1814
        File smFile = files.get("sysmeta");
1815
        FileInputStream sysmeta = new FileInputStream(smFile);
1816
        SystemMetadata systemMetadata = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysmeta);
1817

    
1818
        logMetacat.debug("updating system metadata with pid " + pid.getValue());
1819
        
1820
        CNodeService.getInstance(request).updateSystemMetadata(session, pid, systemMetadata);
1821
    }
1822
    
1823
    private void doViews(String format, String pid) {
1824
        
1825
        OutputStream out = null;
1826
        CNodeService cnode = CNodeService.getInstance(request);
1827

    
1828
        try {
1829
            // get a list of views
1830
            if (pid != null) {
1831
                Identifier identifier = new Identifier();
1832
                identifier.setValue(pid);
1833
                InputStream stream = cnode.view(session, format, identifier);
1834

    
1835
                // set the content-type if we have it from the implementation
1836
                if (stream instanceof ContentTypeInputStream) {
1837
                    response.setContentType(((ContentTypeInputStream) stream).getContentType());
1838
                }
1839
                response.setStatus(200);
1840
                out = response.getOutputStream();
1841
                // write the results to the output stream
1842
                IOUtils.copyLarge(stream, out);
1843
                return;
1844
            } else {
1845
                // TODO: list the registered views
1846
                //BaseException ni = new NotImplemented("9999", "MN.listViews() is not implemented at this node");
1847
                //throw ni;
1848
                OptionList list = cnode.listViews(session);
1849
                
1850
                response.setContentType("text/xml");
1851
                response.setStatus(200);
1852
                TypeMarshaller.marshalTypeToOutputStream(list, response.getOutputStream());
1853
            }
1854
            
1855
            
1856
        } catch (BaseException be) {
1857
            // report Exceptions as clearly as possible
1858
            try {
1859
                out = response.getOutputStream();
1860
            } catch (IOException e) {
1861
                logMetacat.error("Could not get output stream from response", e);
1862
            }
1863
            serializeException(be, out);
1864
        } catch (Exception e) {
1865
            // report Exceptions as clearly and generically as possible
1866
            logMetacat.error(e.getClass() + ": " + e.getMessage(), e);
1867
            try {
1868
                out = response.getOutputStream();
1869
            } catch (IOException ioe) {
1870
                logMetacat.error("Could not get output stream from response", ioe);
1871
            }
1872
            ServiceFailure se = new ServiceFailure("0000", e.getMessage());
1873
            serializeException(se, out);
1874
        }
1875
    }
1876

    
1877
}
(1-1/4)