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: 2011-11-08 15:49:41 -0800 (Tue, 08 Nov 2011) $'
8
 *
9
 * This program is free software; you can redistribute it and/or modify
10
 * it under the terms of the GNU General Public License as published by
11
 * the Free Software Foundation; either version 2 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program; if not, write to the Free Software
21
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
 */
23
package edu.ucsb.nceas.metacat.restservice;
24

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

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

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

    
77
import edu.ucsb.nceas.metacat.dataone.CNodeService;
78

    
79
/**
80
 * CN REST service implementation handler
81
 * 
82
 * ******************
83
 	CNCore -- DONE
84
		create() - POST /d1/cn/object/PID
85
		listFormats() - GET /d1/cn/formats
86
		getFormat() - GET /d1/cn/formats/FMTID
87
		getLogRecords - GET /d1/cn/log
88
		reserveIdentifier() - POST /d1/cn/reserve
89
		listNodes() - Not implemented
90
		registerSystemMetadata() - POST /d1/meta/PID
91
	
92
	CNRead -- DONE
93
		get() - GET /d1/cn/object/PID
94
		getSystemMetadata() - GET /d1/cn/meta/PID
95
		resolve() - GET /d1/cn/resolve/PID
96
		assertRelation() - GET /d1/cn/assertRelation/PID
97
		getChecksum() - GET /d1/cn/checksum
98
		search() - Not implemented in Metacat
99
	
100
	CNAuthorization
101
		setOwner() - PUT /d1/cn/owner/PID
102
		isAuthorized() - GET /d1/cn/isAuthorized/PID
103
		setAccessPolicy() - POST /d1/cn/accessRules
104
		
105
	CNIdentity - not implemented at all on Metacat
106
	
107
	CNReplication
108
		setReplicationStatus() - PUT /replicationNotifications/PID
109
		updateReplicationMetadata() - PUT /replicationMetadata/PID
110
		setReplicationPolicy() - PUT /replicationPolicies/PID
111
		isNodeAuthorized() - GET /replicationAuthorizations/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_ASSERT_RELATION = "assertRelation";
125
    protected static final String RESOURCE_OWNER = "owner";
126
    protected static final String RESOURCE_REPLICATION_POLICY = "replicaPolicies";
127
    protected static final String RESOURCE_REPLICATION_META = "replicaMetadata";
128
    protected static final String RESOURCE_REPLICATION_AUTHORIZED = "replicaAuthorizations";
129
    protected static final String RESOURCE_REPLICATION_NOTIFY = "replicaNotifications";
130
	
131
    public CNResourceHandler(ServletContext servletContext,
132
			HttpServletRequest request, HttpServletResponse response) {
133
		super(servletContext, request, response);
134
        logMetacat = Logger.getLogger(CNResourceHandler.class);
135
	}
136

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

    
149
        	// get the resource
150
            String resource = request.getPathInfo();
151
            resource = resource.substring(resource.indexOf("/") + 1);
152
                        
153
            // for the rest of the resouce
154
            String extra = null;
155
            
156
            logMetacat.debug("handling verb " + httpVerb + " request with resource '" + resource + "'");
157
            boolean status = false;
158

    
159
            if (resource != null) {
160

    
161
                if (resource.startsWith(RESOURCE_ACCESS_RULES) && httpVerb == PUT) {
162
                    logMetacat.debug("Setting access policy");
163
                    // after the command
164
                    extra = parseTrailing(resource, RESOURCE_ACCESS_RULES);
165
                    setAccess(extra);
166
                    status = true;
167
                    logMetacat.debug("done setting access");
168
                    
169
                } else if (resource.startsWith(RESOURCE_META)) {
170
                    logMetacat.debug("Using resource: " + RESOURCE_META);
171
                    
172
                    // after the command
173
                    extra = parseTrailing(resource, RESOURCE_META);
174
                    
175
                    // get
176
                    if (httpVerb == GET) {
177
                        getSystemMetadataObject(extra);
178
                        status = true;
179
                    }
180
                    // post to register system metadata
181
                    if (httpVerb == POST) {
182
                    	registerSystemMetadata(extra);
183
                    	status = true;
184
                    }
185

    
186
                } else if (resource.startsWith(RESOURCE_RESERVE)) {
187
                    // reserve the ID (in params)
188
                    if (httpVerb == POST) {
189
                    	reserve();
190
                    	status = true;
191
                    }
192
                } else if (resource.startsWith(RESOURCE_ASSERT_RELATION)) {
193
                	
194
                	// after the command
195
                    extra = parseTrailing(resource, RESOURCE_ASSERT_RELATION);
196
                    
197
                    // reserve the ID (in params)
198
                    if (httpVerb == GET) {
199
                    	assertRelation(extra);
200
                    	status = true;
201
                    }    
202
                } else if (resource.startsWith(RESOURCE_RESOLVE)) {
203
                	
204
                	// after the command
205
                    extra = parseTrailing(resource, RESOURCE_RESOLVE);
206
                    
207
                    // resolve the object location
208
                    if (httpVerb == GET) {
209
                    	resolve(extra);
210
                    	status = true;
211
                    }
212
                } else if (resource.startsWith(RESOURCE_OWNER)) {
213
                	
214
                	// after the command
215
                    extra = parseTrailing(resource, RESOURCE_OWNER);
216
                    
217
                    // set the owner
218
                    if (httpVerb == PUT) {
219
                    	owner(extra);
220
                    	status = true;
221
                    }    
222
                } else if (resource.startsWith(RESOURCE_IS_AUTHORIZED)) {
223
                	
224
                	// after the command
225
                    extra = parseTrailing(resource, RESOURCE_IS_AUTHORIZED);
226
                    
227
                    // authorized?
228
                    if (httpVerb == GET) {
229
                    	isAuthorized(extra);
230
                    	status = true;
231
                    }    
232
                } else if (resource.startsWith(RESOURCE_OBJECTS)) {
233
                    logMetacat.debug("Using resource 'object'");
234
                    logMetacat.debug("D1 Rest: Starting resource processing...");
235
                    
236
                    // after the command
237
                    extra = parseTrailing(resource, RESOURCE_OBJECTS);
238
                    
239
                    logMetacat.debug("objectId: " + extra);
240
                    logMetacat.debug("verb:" + httpVerb);
241

    
242
                    if (httpVerb == GET) {
243
                    	if (extra != null) {
244
                    		getObject(extra);
245
                    	} else {
246
                    		listObjects();
247
                    	}
248
                        status = true;
249
                    } else if (httpVerb == POST) {
250
                        putObject(extra, FUNCTION_NAME_INSERT);
251
                        status = true;
252
                    }
253
                    
254
                } else if (resource.startsWith(RESOURCE_FORMATS)) {
255
                  logMetacat.debug("Using resource: " + RESOURCE_FORMATS);
256
                  
257
                  // after the command
258
                  extra = parseTrailing(resource, RESOURCE_FORMATS);
259
                  
260
                  // handle each verb
261
                  if (httpVerb == GET) {
262
                  	if (extra == null) {
263
                  		// list the formats collection
264
                  		listFormats();
265
                  	} else {
266
                  		// get the specified format
267
                  		getFormat(extra);
268
                  	}
269
                  	status = true;
270
                  }
271
                  
272
                } else if (resource.startsWith(RESOURCE_LOG)) {
273
                    logMetacat.debug("Using resource: " + RESOURCE_LOG);
274
                    //handle log events
275
                    if (httpVerb == GET) {
276
                        getLog();
277
                        status = true;
278
                    }
279

    
280
                } else if (resource.startsWith(RESOURCE_CHECKSUM)) {
281
                    logMetacat.debug("Using resource: " + RESOURCE_CHECKSUM);
282
                    
283
                    // after the command
284
                    extra = parseTrailing(resource, RESOURCE_CHECKSUM);
285
                    
286
                    //handle checksum requests
287
                    if (httpVerb == GET) {
288
                    
289
                        checksum(extra);
290
                        status = true;
291
                        
292
                    }
293
                
294
                } else if ( resource.startsWith(RESOURCE_REPLICATION_POLICY) && 
295
                        httpVerb == PUT) {
296
                    
297
                    logMetacat.debug("Using resource: " + RESOURCE_REPLICATION_POLICY);
298
                    // get the trailing pid
299
                    extra = parseTrailing(resource, RESOURCE_REPLICATION_POLICY);
300
                    setReplicationPolicy(extra);
301
                    status = true;
302

    
303
                } else if ( resource.startsWith(RESOURCE_REPLICATION_META) && 
304
                        httpVerb == PUT) {
305
                    
306
                    logMetacat.debug("Using resource: " + RESOURCE_REPLICATION_META);
307
                    // get the trailing pid
308
                    extra = parseTrailing(resource, RESOURCE_REPLICATION_META);
309
                    updateReplicationMetadata(extra);
310
                    status = true;
311

    
312
                } else if ( resource.startsWith(RESOURCE_REPLICATION_NOTIFY) && 
313
                        httpVerb == PUT ) {
314
                    
315
                    logMetacat.debug("Using resource: " + RESOURCE_REPLICATION_NOTIFY);
316
                    // get the trailing pid
317
                    extra = parseTrailing(resource, RESOURCE_REPLICATION_NOTIFY);
318
                    setReplicationStatus(extra);
319
                    status = true;
320
                    
321
                } else if ( resource.startsWith(RESOURCE_REPLICATION_AUTHORIZED) 
322
                        && httpVerb == GET) {
323
                    
324
                    logMetacat.debug("Using resource: " + RESOURCE_REPLICATION_AUTHORIZED);
325
                    // get the trailing pid
326
                    extra = parseTrailing(resource, RESOURCE_REPLICATION_AUTHORIZED);
327
                    isNodeAuthorized(extra);
328
                    status = true;
329
                    
330
                } 
331
                    
332
                if (!status) {
333
                	throw new ServiceFailure("0000", "Unknown error, status = " + status);
334
                }
335
            } else {
336
            	throw new InvalidRequest("0000", "No resource matched for " + resource);
337
            }
338
        } catch (BaseException be) {
339
        	// report Exceptions as clearly and generically as possible
340
        	OutputStream out = null;
341
			try {
342
				out = response.getOutputStream();
343
			} catch (IOException ioe) {
344
				logMetacat.error("Could not get output stream from response", ioe);
345
			}
346
            serializeException(be, out);
347
        } catch (Exception e) {
348
            // report Exceptions as clearly and generically as possible
349
            logMetacat.error(e.getClass() + ": " + e.getMessage(), e);
350
        	OutputStream out = null;
351
			try {
352
				out = response.getOutputStream();
353
			} catch (IOException ioe) {
354
				logMetacat.error("Could not get output stream from response", ioe);
355
			}
356
			ServiceFailure se = new ServiceFailure("0000", e.getMessage());
357
            serializeException(se, out);
358
        }
359
    }
360
    
361
    
362
    /**
363
     * Get the checksum for the given guid
364
     * 
365
     * @param guid
366
     * @throws NotImplemented 
367
     * @throws InvalidRequest 
368
     * @throws NotFound 
369
     * @throws NotAuthorized 
370
     * @throws ServiceFailure 
371
     * @throws InvalidToken 
372
     * @throws IOException 
373
     * @throws JiBXException 
374
     */
375
    private void checksum(String guid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, InvalidRequest, NotImplemented, JiBXException, IOException {
376
    	Identifier guidid = new Identifier();
377
        guidid.setValue(guid);
378
        logMetacat.debug("getting checksum for object " + guid);
379
        Checksum c = CNodeService.getInstance(request).getChecksum(session, guidid);
380
        logMetacat.debug("got checksum " + c.getValue());
381
        response.setStatus(200);
382
        logMetacat.debug("serializing response");
383
        TypeMarshaller.marshalTypeToOutputStream(c, response.getOutputStream());
384
        logMetacat.debug("done serializing response.");
385
        
386
    }
387
    
388
	/**
389
     * get the logs based on passed params.  Available 
390
     * params are token, fromDate, toDate, event.  See 
391
     * http://mule1.dataone.org/ArchitectureDocs/mn_api_crud.html#MN_crud.getLogRecords
392
     * for more info
393
	 * @throws NotImplemented 
394
	 * @throws InvalidRequest 
395
	 * @throws NotAuthorized 
396
	 * @throws ServiceFailure 
397
	 * @throws InvalidToken 
398
	 * @throws IOException 
399
	 * @throws JiBXException 
400
     */
401
    private void getLog() throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest, NotImplemented, IOException, JiBXException
402
    {
403
        
404
        Date fromDate = null;
405
        Date toDate = null;
406
        Event event = null;
407
        Integer start = null;
408
        Integer count = null;
409
        
410
        try {
411
        	String fromDateS = params.get("fromDate")[0];
412
            logMetacat.debug("param fromDateS: " + fromDateS);
413
            fromDate = DateTimeMarshaller.deserializeDateToUTC(fromDateS);
414
        } catch (Exception e) {
415
        	logMetacat.warn("Could not parse fromDate: " + e.getMessage());
416
        }
417
        try {
418
        	String toDateS = params.get("toDate")[0];
419
            logMetacat.debug("param toDateS: " + toDateS);
420
            toDate = DateTimeMarshaller.deserializeDateToUTC(toDateS);
421
        } catch (Exception e) {
422
        	logMetacat.warn("Could not parse toDate: " + e.getMessage());
423
		}
424
        try {
425
        	String eventS = params.get("event")[0];
426
            event = Event.convert(eventS);
427
        } catch (Exception e) {
428
        	logMetacat.warn("Could not parse event: " + e.getMessage());
429
		}
430
        logMetacat.debug("fromDate: " + fromDate + " toDate: " + toDate);
431
        
432
        try {
433
        	start =  Integer.parseInt(params.get("start")[0]);
434
        } catch (Exception e) {
435
			logMetacat.warn("Could not parse start: " + e.getMessage());
436
		}
437
        try {
438
        	count =  Integer.parseInt(params.get("count")[0]);
439
        } catch (Exception e) {
440
			logMetacat.warn("Could not parse count: " + e.getMessage());
441
		}
442
        
443
        logMetacat.debug("calling getLogRecords");
444
        Log log = CNodeService.getInstance(request).getLogRecords(session, fromDate, toDate, event, start, count);
445
        
446
        OutputStream out = response.getOutputStream();
447
        response.setStatus(200);
448
        response.setContentType("text/xml");
449
        
450
        TypeMarshaller.marshalTypeToOutputStream(log, out);
451
  
452
    }
453

    
454
    /**
455
     * Implements REST version of DataONE CRUD API --> get
456
     * @param guid ID of data object to be read
457
     * @throws NotImplemented 
458
     * @throws InvalidRequest 
459
     * @throws NotFound 
460
     * @throws NotAuthorized 
461
     * @throws ServiceFailure 
462
     * @throws InvalidToken 
463
     * @throws IOException 
464
     */
465
    protected void getObject(String guid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, InvalidRequest, NotImplemented, IOException {
466

    
467
        Identifier id = new Identifier();
468
        id.setValue(guid);
469
            
470
        SystemMetadata sm = CNodeService.getInstance(request).getSystemMetadata(session, id);
471
        
472
        //set the content type
473
        if(sm.getFormatId().getValue().trim().equals(
474
        		ObjectFormatCache.getInstance().getFormat("text/csv").getFormatId().getValue()))
475
        {
476
            response.setContentType("text/csv");
477
            response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".csv");
478
        }
479
        else if(sm.getFormatId().getValue().trim().equals(
480
        		ObjectFormatCache.getInstance().getFormat("text/plain").getFormatId().getValue()))
481
        {
482
            response.setContentType("text/plain");
483
            response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".txt");
484
        } 
485
        else if(sm.getFormatId().getValue().trim().equals(
486
        		ObjectFormatCache.getInstance().getFormat("application/octet-stream").getFormatId().getValue()))
487
        {
488
            response.setContentType("application/octet-stream");
489
        }
490
        else
491
        {
492
            response.setContentType("text/xml");
493
            response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".xml");
494
        }
495
        
496
        InputStream data = CNodeService.getInstance(request).get(session, id);
497
        
498
        OutputStream out = response.getOutputStream();
499
        response.setStatus(200);
500
        IOUtils.copyLarge(data, out);
501
            
502
    }
503
    
504

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

    
519
        Identifier id = new Identifier();
520
        id.setValue(guid);
521
        SystemMetadata sysmeta = CNodeService.getInstance(request).getSystemMetadata(session, id);
522
        
523
        response.setContentType("text/xml");
524
        response.setStatus(200);
525
        OutputStream out = response.getOutputStream();
526
        
527
        // Serialize and write it to the output stream
528
        TypeMarshaller.marshalTypeToOutputStream(sysmeta, out);
529
   }
530
    
531
    /**
532
     * Earthgrid API > Put Service >Put Function : calls MetacatHandler > handleInsertOrUpdateAction 
533
     * 
534
     * @param guid - ID of data object to be inserted or updated.  If action is update, the pid
535
     *               is the existing pid.  If insert, the pid is the new one
536
     * @throws InvalidRequest 
537
     * @throws ServiceFailure 
538
     * @throws IdentifierNotUnique 
539
     * @throws JiBXException 
540
     * @throws NotImplemented 
541
     * @throws InvalidSystemMetadata 
542
     * @throws InsufficientResources 
543
     * @throws UnsupportedType 
544
     * @throws NotAuthorized 
545
     * @throws InvalidToken 
546
     * @throws IOException 
547
     * @throws IllegalAccessException 
548
     * @throws InstantiationException 
549
     */
550
    protected void putObject(String pid, String action) throws ServiceFailure, InvalidRequest, IdentifierNotUnique, JiBXException, InvalidToken, NotAuthorized, UnsupportedType, InsufficientResources, InvalidSystemMetadata, NotImplemented, IOException, InstantiationException, IllegalAccessException {
551
        logMetacat.debug("Entering putObject: " + pid + "/" + action);
552
        
553
        // Read the incoming data from its Mime Multipart encoding
554
    	Map<String, File> files = collectMultipartFiles();
555
        InputStream object = null;
556
        InputStream sysmeta = null;
557

    
558
        File smFile = files.get("sysmeta");
559
        sysmeta = new FileInputStream(smFile);
560
        File objFile = files.get("object");
561
        object = new FileInputStream(objFile);
562
       
563
        if (action.equals(FUNCTION_NAME_INSERT)) { //handle inserts
564

    
565
            logMetacat.debug("Commence creation...");
566
            SystemMetadata smd = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysmeta);
567

    
568
            Identifier id = new Identifier();
569
            id.setValue(pid);
570
            logMetacat.debug("creating object with pid " + id.getValue());
571
            Identifier rId = CNodeService.getInstance(request).create(session, id, object, smd);
572
            
573
            OutputStream out = response.getOutputStream();
574
            response.setStatus(200);
575
            response.setContentType("text/xml");
576
            
577
            TypeMarshaller.marshalTypeToOutputStream(rId, out);
578
            
579
        } else {
580
            throw new InvalidRequest("1000", "Operation must be create.");
581
        }
582
    }
583

    
584
    /**
585
     * List the object formats registered with the system
586
     * @throws NotImplemented 
587
     * @throws InsufficientResources 
588
     * @throws NotFound 
589
     * @throws ServiceFailure 
590
     * @throws InvalidRequest 
591
     * @throws IOException 
592
     * @throws JiBXException 
593
     */
594
	private void listFormats() throws InvalidRequest, ServiceFailure, NotFound, InsufficientResources, NotImplemented, IOException, JiBXException {
595
      logMetacat.debug("Entering listFormats()");
596

    
597
      ObjectFormatList objectFormatList = CNodeService.getInstance(request).listFormats();
598
      // get the response output stream
599
      OutputStream out = response.getOutputStream();
600
      response.setStatus(200);
601
      response.setContentType("text/xml");
602
      
603
      TypeMarshaller.marshalTypeToOutputStream(objectFormatList, out);
604
            
605
    }
606

    
607
		/**
608
     * Return the requested object format
609
     * 
610
     * @param fmtidStr the requested format identifier as a string
611
		 * @throws NotImplemented 
612
		 * @throws InsufficientResources 
613
		 * @throws NotFound 
614
		 * @throws ServiceFailure 
615
		 * @throws InvalidRequest 
616
		 * @throws IOException 
617
		 * @throws JiBXException 
618
     */
619
    private void getFormat(String fmtidStr) throws InvalidRequest, ServiceFailure, NotFound, InsufficientResources, NotImplemented, IOException, JiBXException {
620
      logMetacat.debug("Entering listFormats()");
621
      
622
      ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
623
      fmtid.setValue(fmtidStr);
624
      
625
	  // get the specified object format
626
      ObjectFormat objectFormat = CNodeService.getInstance(request).getFormat(fmtid);
627
      
628
      OutputStream out = response.getOutputStream();
629
      response.setStatus(200);
630
      response.setContentType("text/xml");
631
      
632
      TypeMarshaller.marshalTypeToOutputStream(objectFormat, out);
633
      
634
    }
635
    
636
    /**
637
     * Reserve the given Identifier
638
     * @throws InvalidToken
639
     * @throws ServiceFailure
640
     * @throws NotAuthorized
641
     * @throws IdentifierNotUnique
642
     * @throws NotImplemented
643
     * @throws InvalidRequest
644
     * @throws IOException 
645
     * @throws JiBXException 
646
     */
647
    private void reserve() throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique, NotImplemented, InvalidRequest, IOException, JiBXException {
648
		Identifier pid = null;
649
		String scope = null;
650
    	String format = null;
651
    	// gather the params
652
		try {
653
	    	String id = params.get("pid")[0];
654
			pid = new Identifier();
655
			pid.setValue(id);
656
		} catch (Exception e) {
657
			logMetacat.warn("pid not specified");
658
		}
659
		try {
660
			scope = params.get("scope")[0];
661
		} catch (Exception e) {
662
			logMetacat.warn("pid not specified");
663
		}
664
		try {
665
			format = params.get("format")[0];
666
		} catch (Exception e) {
667
			logMetacat.warn("pid not specified");
668
		} 
669
		// call the implementation
670
		Identifier resultPid = CNodeService.getInstance(request).reserveIdentifier(session, pid);
671
		OutputStream out = response.getOutputStream();
672
		response.setStatus(200);
673
		response.setContentType("text/xml");
674
		// send back the reserved pid
675
		TypeMarshaller.marshalTypeToOutputStream(resultPid, out);
676
    }
677
    
678
    /**
679
     * 
680
     * @param id
681
     * @throws InvalidRequest
682
     * @throws InvalidToken
683
     * @throws ServiceFailure
684
     * @throws NotAuthorized
685
     * @throws NotFound
686
     * @throws NotImplemented
687
     * @throws IOException
688
     * @throws JiBXException 
689
     */
690
    private void resolve(String id) throws InvalidRequest, InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, IOException, JiBXException {
691
		Identifier pid = new Identifier();
692
		pid.setValue(id);
693
		ObjectLocationList locationList = CNodeService.getInstance(request).resolve(session, pid);
694
	    OutputStream out = response.getOutputStream();
695
		response.setStatus(200);
696
		response.setContentType("text/xml");
697
		TypeMarshaller.marshalTypeToOutputStream(locationList, out);
698
		
699
    }
700

    
701
    /**
702
     * Assert that a relationship exists between two resources
703
     * @param id
704
     * @return
705
     * @throws InvalidToken
706
     * @throws ServiceFailure
707
     * @throws NotAuthorized
708
     * @throws NotFound
709
     * @throws InvalidRequest
710
     * @throws NotImplemented
711
     */
712
    private boolean assertRelation(String id) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, InvalidRequest, NotImplemented {
713
		Identifier pidOfSubject = new Identifier();
714
		pidOfSubject.setValue(id);
715
		String relationship = null;
716
		try {
717
			relationship = params.get("relationship")[0];
718
		} catch (Exception e) {
719
			logMetacat.warn("relationship not specified");
720
		}
721
		Identifier pidOfObject = new Identifier();
722
		try {
723
			String objPid = params.get("pidOfObject")[0];
724
			pidOfObject.setValue(objPid);
725
		} catch (Exception e) {
726
			logMetacat.warn("pidOfObject not specified");
727
		}
728
		boolean result = CNodeService.getInstance(request).assertRelation(session, pidOfSubject, relationship, pidOfObject);
729
		response.setStatus(200);
730
		response.setContentType("text/xml");
731
		return result;
732
    }
733
    
734
    /**
735
     * Set the owner of a resource
736
     * @param id
737
     * @throws JiBXException
738
     * @throws InvalidToken
739
     * @throws ServiceFailure
740
     * @throws NotFound
741
     * @throws NotAuthorized
742
     * @throws NotImplemented
743
     * @throws InvalidRequest
744
     * @throws IOException
745
     * @throws IllegalAccessException 
746
     * @throws InstantiationException 
747
     */
748
    private void owner(String id) 
749
        throws JiBXException, InvalidToken, ServiceFailure, 
750
        NotFound, NotAuthorized, NotImplemented, InvalidRequest, IOException, 
751
        InstantiationException, IllegalAccessException {
752
		
753
        Identifier pid = new Identifier();
754
		    pid.setValue(id);
755

    
756
        long serialVersion = 0L;
757
        String serialVersionStr = null;
758
        
759
        // get the serialVersion
760
        try {
761
            serialVersionStr = params.get("serialVersion")[0];
762
            serialVersion = new Long(serialVersionStr).longValue();
763
            
764
        } catch (NullPointerException e) {
765
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
766
            logMetacat.error(msg);
767
            throw new InvalidRequest("4442", msg);
768
            
769
        }		    
770
		    
771
		    // get the subject
772
		    String subjectStr = params.get("subject")[0];
773
		    Subject subject = TypeMarshaller.unmarshalTypeFromStream(Subject.class, new ByteArrayInputStream(subjectStr.getBytes("UTF-8")));
774
		    
775
		    Identifier retPid = CNodeService.getInstance(request).setOwner(session, pid, subject, serialVersion);
776
		    OutputStream out = response.getOutputStream();
777
		    response.setStatus(200);
778
		    response.setContentType("text/xml");
779
		    TypeMarshaller.marshalTypeToOutputStream(retPid, out);		
780
    }
781
    
782
    /**
783
     * Processes the authorization check for given id
784
     * @param id
785
     * @return
786
     * @throws ServiceFailure
787
     * @throws InvalidToken
788
     * @throws NotFound
789
     * @throws NotAuthorized
790
     * @throws NotImplemented
791
     * @throws InvalidRequest
792
     */
793
    private boolean isAuthorized(String id) throws ServiceFailure, InvalidToken, NotFound, NotAuthorized, NotImplemented, InvalidRequest {
794
		Identifier pid = new Identifier();
795
		pid.setValue(id);
796
		String permission = params.get("action")[0];
797
		boolean result = CNodeService.getInstance(request).isAuthorized(session, pid, Permission.convert(permission));
798
		response.setStatus(200);
799
		response.setContentType("text/xml");
800
		return result;
801
    }
802
    
803
    /**
804
     * Register System Metadata without data or metadata object
805
     * @param pid identifier for System Metadata entry
806
     * @throws JiBXException 
807
     * @throws FileUploadException 
808
     * @throws IOException 
809
     * @throws InvalidRequest 
810
     * @throws ServiceFailure 
811
     * @throws InvalidSystemMetadata 
812
     * @throws NotAuthorized 
813
     * @throws NotImplemented 
814
     * @throws IllegalAccessException 
815
     * @throws InstantiationException 
816
     */
817
    protected Identifier registerSystemMetadata(String pid) throws ServiceFailure, InvalidRequest, IOException, FileUploadException, JiBXException, NotImplemented, NotAuthorized, InvalidSystemMetadata, InstantiationException, IllegalAccessException {
818
		logMetacat.debug("Entering registerSystemMetadata: " + pid);
819

    
820
		// get the system metadata from the request
821
		SystemMetadata systemMetadata = collectSystemMetadata();
822

    
823
		Identifier guid = new Identifier();
824
		guid.setValue(pid);
825
		logMetacat.debug("registering system metadata with pid " + guid.getValue());
826
		Identifier retGuid = CNodeService.getInstance(request).registerSystemMetadata(session, guid, systemMetadata);
827
		
828
		response.setStatus(200);
829
		response.setContentType("text/xml");
830
		return retGuid;
831
			
832
	}
833
    
834
    /**
835
     * set the access perms on a document
836
     * @throws JiBXException 
837
     * @throws InvalidRequest 
838
     * @throws NotImplemented 
839
     * @throws NotAuthorized 
840
     * @throws NotFound 
841
     * @throws ServiceFailure 
842
     * @throws InvalidToken 
843
     * @throws IllegalAccessException 
844
     * @throws InstantiationException 
845
     * @throws IOException 
846
     * @throws SAXException 
847
     * @throws ParserConfigurationException 
848
     */
849
    protected void setAccess(String pid) 
850
        throws JiBXException, InvalidToken, ServiceFailure, NotFound, 
851
        NotAuthorized, NotImplemented, InvalidRequest, IOException, 
852
        InstantiationException, IllegalAccessException, ParserConfigurationException, 
853
        SAXException {
854

    
855
        long serialVersion = 0L;
856
        String serialVersionStr = null;
857
        
858
        // get the serialVersion
859
        try {
860
            serialVersionStr = params.get("serialVersion")[0];
861
            serialVersion = new Long(serialVersionStr).longValue();
862
            
863
        } catch (NullPointerException e) {
864
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
865
            logMetacat.error(msg);
866
            throw new InvalidRequest("4402", msg);
867
            
868
        }
869
        
870
        Identifier id = new Identifier();
871
        id.setValue(pid);
872
        
873
        AccessPolicy accessPolicy = collectAccessPolicy();
874
        CNodeService.getInstance(request).setAccessPolicy(session, id, accessPolicy, serialVersion);
875

    
876
    }
877
    
878
    /**
879
     *	List the objects
880
     *
881
     * @throws NotImplemented 
882
     * @throws InvalidRequest 
883
     * @throws NotAuthorized 
884
     * @throws ServiceFailure 
885
     * @throws InvalidToken 
886
     * @throws NotFound 
887
     * @throws IOException 
888
     * @throws JiBXException
889
     * @throws Exception
890
     */
891
    private void listObjects() throws InvalidToken, ServiceFailure, NotAuthorized,
892
			InvalidRequest, NotImplemented, NotFound, IOException,
893
			JiBXException {
894

    
895
		Date startTime = null;
896
		Date endTime = null;
897
		ObjectFormat objectFormat = null;
898
		boolean replicaStatus = false;
899
		int start = 0;
900
		int count = -1;
901
		Enumeration<String> paramlist = request.getParameterNames();
902
		while (paramlist.hasMoreElements()) {
903
			// parse the params and make the call
904
			String name = paramlist.nextElement();
905
			String[] value = request.getParameterValues(name);
906

    
907
			if (name.equals("startTime") && value != null) {
908
				try {
909
					startTime = DateTimeMarshaller.deserializeDateToUTC(value[0]);
910
				} catch (Exception e) { 
911
					// if we can't parse it, just don't use the startTime param
912
					logMetacat.warn("Could not parse startTime: " + value[0]);
913
					startTime = null;
914
				}
915
			} else if (name.equals("endTime") && value != null) {
916
				try {
917
					endTime = DateTimeMarshaller.deserializeDateToUTC(value[0]);
918
				} catch (Exception e) { 
919
					// if we can't parse it, just don't use the endTime param
920
					logMetacat.warn("Could not parse endTime: " + value[0]);
921
					endTime = null;
922
				}
923
			} else if (name.equals("objectFormat") && value != null) {
924
				objectFormat = ObjectFormatCache.getInstance().getFormat(value[0]);
925
			} else if (name.equals("replicaStatus") && value != null) {
926
				replicaStatus = Boolean.parseBoolean(value[0]);
927
			} else if (name.equals("start") && value != null) {
928
				start = Integer.valueOf(value[0]);
929
			} else if (name.equals("count") && value != null) {
930
				count = Integer.valueOf(value[0]);
931
			}
932
		}
933
		// make the call
934
		logMetacat.debug("session: " + session + " startTime: " + startTime
935
				+ " endtime: " + endTime + " objectFormat: " + objectFormat
936
				+ " replicaStatus: " + replicaStatus + " start: " + start
937
				+ " count: " + count);
938

    
939
		ObjectFormatIdentifier fmtid = null;
940
		if (objectFormat != null) {
941
			fmtid = objectFormat.getFormatId();
942
		}
943
		
944
		// get the list
945
		ObjectList ol = 
946
			CNodeService.getInstance(request).listObjects(session,
947
				startTime, endTime, fmtid, replicaStatus, start, count);
948

    
949
		// send it
950
		OutputStream out = response.getOutputStream();
951
		response.setStatus(200);
952
		response.setContentType("text/xml");
953
		// Serialize and write it to the output stream
954
		TypeMarshaller.marshalTypeToOutputStream(ol, out);
955
	}
956
    
957
    /**
958
     * Pass the request to get node replication authorization to CNodeService
959
     * 
960
     * @param pid  the identifier of the object to get authorization to replicate
961
     * 
962
     * @throws NotImplemented
963
     * @throws NotAuthorized
964
     * @throws InvalidToken
965
     * @throws ServiceFailure
966
     * @throws NotFound
967
     * @throws InvalidRequest
968
     */
969
    public boolean isNodeAuthorized(String pid) 
970
        throws NotImplemented, NotAuthorized, InvalidToken, ServiceFailure, 
971
        NotFound, InvalidRequest {
972
        
973
        boolean result = false;
974
        Subject targetNodeSubject = new Subject();
975
        String nodeSubject = null;
976
        Permission permission = null;
977
        String replPermission = null;
978
        
979
        // get the pid
980
        Identifier identifier = new Identifier();
981
        identifier.setValue(pid);
982
        
983
        // get the target node subject
984
        try {
985
            nodeSubject = params.get("targetNodeSubject")[0];
986
            targetNodeSubject.setValue(nodeSubject);
987
            
988
        } catch (NullPointerException e) {
989
            String msg = "The 'targetNodeSubject' must be provided as a parameter and was not.";
990
            logMetacat.error(msg);
991
            throw new InvalidRequest("4873", msg);
992
            
993
        }
994
        
995
        // get the permission
996
        try {
997
            replPermission = params.get("replicatePermission")[0];
998
            permission = Permission.convert(replPermission);
999

    
1000
        } catch (NullPointerException e) {
1001
            String msg = "The 'replicatePermission' must be provided as a parameter and was not.";
1002
            logMetacat.error(msg);
1003
            throw new InvalidRequest("4873", msg);
1004

    
1005
        }
1006
        
1007
        result =
1008
            CNodeService.getInstance(request).isNodeAuthorized(session, targetNodeSubject, identifier, permission);
1009
        
1010
        response.setStatus(200);
1011
        response.setContentType("text/xml");
1012
        return result;
1013
        
1014
    }
1015
    
1016
    /**
1017
     * Pass the request to set the replication policy to CNodeService
1018
     * 
1019
     * @param pid  the identifier of the object to set the replication policy on
1020
     * 
1021
     * @throws NotImplemented
1022
     * @throws NotFound
1023
     * @throws NotAuthorized
1024
     * @throws ServiceFailure
1025
     * @throws InvalidRequest
1026
     * @throws InvalidToken
1027
     * @throws IOException
1028
     * @throws InstantiationException
1029
     * @throws IllegalAccessException
1030
     * @throws JiBXException
1031
     */
1032
    public boolean setReplicationPolicy(String pid) 
1033
        throws NotImplemented, NotFound, NotAuthorized, ServiceFailure, 
1034
        InvalidRequest, InvalidToken, IOException, InstantiationException, 
1035
        IllegalAccessException, JiBXException {
1036
        
1037
        boolean result = false;
1038
        ReplicationPolicy policy = null;
1039
        long serialVersion = 0L;
1040
        String serialVersionStr = null;
1041
       
1042
        Identifier identifier = new Identifier();
1043
        identifier.setValue(pid);
1044
        
1045
        // get the serialVersion
1046
        try {
1047
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1048
            serialVersion = new Long(serialVersionStr).longValue();
1049
            
1050
        } catch (NullPointerException e) {
1051
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1052
            logMetacat.error(msg);
1053
            throw new InvalidRequest("4883", msg);
1054
            
1055
        }
1056
        policy = collectReplicationPolicy();
1057
        result = 
1058
            CNodeService.getInstance(request).setReplicationPolicy(session, identifier, policy, serialVersion);
1059
        response.setStatus(200);
1060
        response.setContentType("text/xml");
1061
        return result;
1062
        
1063
    }
1064
    
1065
    /**
1066
     * Pass the request to set the replication status to CNodeService
1067
     * 
1068
     * @param pid  the identifier of the object to set the replication status on
1069
     * 
1070
     * @throws ServiceFailure
1071
     * @throws NotImplemented
1072
     * @throws InvalidToken
1073
     * @throws NotAuthorized
1074
     * @throws InvalidRequest
1075
     * @throws NotFound
1076
     */
1077
    public boolean setReplicationStatus(String pid) 
1078
        throws ServiceFailure, NotImplemented, InvalidToken, NotAuthorized, 
1079
        InvalidRequest, NotFound {
1080

    
1081
        boolean result = false;
1082
        Identifier identifier = new Identifier();
1083
        identifier.setValue(pid);
1084
        long serialVersion = 0L;
1085
        String serialVersionStr = null;
1086
        ReplicationStatus status = null;
1087
        String replicationStatus = null;
1088
        NodeReference targetNodeRef = null;
1089
        String targetNode = null;
1090
        
1091
        // get the serialVersion
1092
        try {
1093
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1094
            serialVersion = new Long(serialVersionStr).longValue();
1095
            
1096
        } catch (NullPointerException e) {
1097
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1098
            logMetacat.error(msg);
1099
            throw new InvalidRequest("4730", msg);
1100
            
1101
        }
1102
        
1103
        // get the replication status param
1104
        try {
1105
            replicationStatus = multipartparams.get("replicationStatus").get(0);
1106
            status = ReplicationStatus.convert(replicationStatus);
1107
        } catch (Exception e) {
1108
            // TODO Auto-generated catch block
1109
            e.printStackTrace();
1110
        }
1111
        
1112
        // get the target node reference param
1113
        targetNode = multipartparams.get("nodeRef").get(0);
1114
        targetNodeRef = new NodeReference();
1115
        targetNodeRef.setValue(targetNode);
1116
        
1117
        result = 
1118
            CNodeService.getInstance(request).setReplicationStatus(session, identifier, targetNodeRef, status, serialVersion);       
1119
        response.setStatus(200);
1120
        response.setContentType("text/xml");
1121
        return result;
1122
        
1123
    }
1124
    
1125
    /**
1126
     * Pass the request to update the replication metadata to CNodeService
1127
     * 
1128
     * @param pid  the identifier of the object to update the replication metadata on
1129
     * 
1130
     * @throws ServiceFailure
1131
     * @throws NotImplemented
1132
     * @throws InvalidToken
1133
     * @throws NotAuthorized
1134
     * @throws InvalidRequest
1135
     * @throws NotFound
1136
     */
1137
    public boolean updateReplicationMetadata(String pid) 
1138
        throws ServiceFailure, NotImplemented, InvalidToken, NotAuthorized, 
1139
        InvalidRequest, NotFound {
1140

    
1141
        boolean result = false;
1142
        long serialVersion = 0L;
1143
        String serialVersionStr = null;
1144
        Replica replica = null;
1145
        Identifier identifier = new Identifier();
1146
        identifier.setValue(pid);
1147

    
1148
        // get the serialVersion
1149
        try {
1150
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1151
            serialVersion = new Long(serialVersionStr).longValue();
1152
            
1153
        } catch (NullPointerException e) {
1154
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1155
            logMetacat.error(msg);
1156
            throw new InvalidRequest("4853", msg);
1157
            
1158
        }
1159

    
1160
        replica = collectReplicaMetadata();
1161
        result = 
1162
            CNodeService.getInstance(request).updateReplicationMetadata(session, identifier, replica, serialVersion);
1163
        response.setStatus(200);
1164
        response.setContentType("text/xml");
1165
        return result;
1166

    
1167
    }
1168

    
1169
}
(1-1/9)