Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *  Copyright: 2011 Regents of the University of California and the
4
 *              National Center for Ecological Analysis and Synthesis
5
 *
6
 *   '$Author: cjones $'
7
 *     '$Date: 2011-11-10 12:07:14 -0800 (Thu, 10 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.mimemultipart.MultipartRequest;
45
import org.dataone.mimemultipart.MultipartRequestResolver;
46
import org.dataone.service.exceptions.BaseException;
47
import org.dataone.service.exceptions.IdentifierNotUnique;
48
import org.dataone.service.exceptions.InsufficientResources;
49
import org.dataone.service.exceptions.InvalidRequest;
50
import org.dataone.service.exceptions.InvalidSystemMetadata;
51
import org.dataone.service.exceptions.InvalidToken;
52
import org.dataone.service.exceptions.NotAuthorized;
53
import org.dataone.service.exceptions.NotFound;
54
import org.dataone.service.exceptions.NotImplemented;
55
import org.dataone.service.exceptions.ServiceFailure;
56
import org.dataone.service.exceptions.UnsupportedType;
57
import org.dataone.service.types.v1.AccessPolicy;
58
import org.dataone.service.types.v1.Checksum;
59
import org.dataone.service.types.v1.Event;
60
import org.dataone.service.types.v1.Identifier;
61
import org.dataone.service.types.v1.Log;
62
import org.dataone.service.types.v1.NodeReference;
63
import org.dataone.service.types.v1.ObjectFormat;
64
import org.dataone.service.types.v1.ObjectFormatIdentifier;
65
import org.dataone.service.types.v1.ObjectFormatList;
66
import org.dataone.service.types.v1.ObjectList;
67
import org.dataone.service.types.v1.ObjectLocationList;
68
import org.dataone.service.types.v1.Permission;
69
import org.dataone.service.types.v1.Replica;
70
import org.dataone.service.types.v1.ReplicationPolicy;
71
import org.dataone.service.types.v1.ReplicationStatus;
72
import org.dataone.service.types.v1.Subject;
73
import org.dataone.service.types.v1.SystemMetadata;
74
import org.dataone.service.util.DateTimeMarshaller;
75
import org.dataone.service.util.TypeMarshaller;
76
import org.jibx.runtime.JiBXException;
77
import org.xml.sax.SAXException;
78

    
79
import edu.ucsb.nceas.metacat.dataone.CNodeService;
80

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

    
122
	/** CN-specific operations **/
123
    protected static final String RESOURCE_RESERVE = "reserve";
124
    protected static final String RESOURCE_FORMATS = "formats";
125
    protected static final String RESOURCE_RESOLVE = "resolve";
126
    protected static final String RESOURCE_ASSERT_RELATION = "assertRelation";
127
    protected static final String RESOURCE_OWNER = "owner";
128
    protected static final String RESOURCE_REPLICATION_POLICY = "replicaPolicies";
129
    protected static final String RESOURCE_REPLICATION_META = "replicaMetadata";
130
    protected static final String RESOURCE_REPLICATION_AUTHORIZED = "replicaAuthorizations";
131
    protected static final String RESOURCE_REPLICATION_NOTIFY = "replicaNotifications";
132
	
133
    public CNResourceHandler(ServletContext servletContext,
134
			HttpServletRequest request, HttpServletResponse response) {
135
		super(servletContext, request, response);
136
        logMetacat = Logger.getLogger(CNResourceHandler.class);
137
	}
138

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

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

    
161
            if (resource != null) {
162

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
822
		// get the system metadata from the request
823
		SystemMetadata systemMetadata = collectSystemMetadata();
824

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

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

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

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

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

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

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

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

    
1007
        }
1008
        
1009
        result =
1010
            CNodeService.getInstance(request).isNodeAuthorized(session, targetNodeSubject, identifier, permission);
1011
        
1012
        response.setStatus(200);
1013
        response.setContentType("text/xml");
1014
        return result;
1015
        
1016
    }
1017
    
1018
    /**
1019
     * Pass the request to set the replication policy to CNodeService
1020
     * 
1021
     * @param pid  the identifier of the object to set the replication policy on
1022
     * 
1023
     * @throws NotImplemented
1024
     * @throws NotFound
1025
     * @throws NotAuthorized
1026
     * @throws ServiceFailure
1027
     * @throws InvalidRequest
1028
     * @throws InvalidToken
1029
     * @throws IOException
1030
     * @throws InstantiationException
1031
     * @throws IllegalAccessException
1032
     * @throws JiBXException
1033
     */
1034
    public boolean setReplicationPolicy(String pid) 
1035
        throws NotImplemented, NotFound, NotAuthorized, ServiceFailure, 
1036
        InvalidRequest, InvalidToken, IOException, InstantiationException, 
1037
        IllegalAccessException, JiBXException {
1038
        
1039
        boolean result = false;
1040
        ReplicationPolicy policy = null;
1041
        long serialVersion = 0L;
1042
        String serialVersionStr = null;
1043
       
1044
        Identifier identifier = new Identifier();
1045
        identifier.setValue(pid);
1046
        
1047
        policy = collectReplicationPolicy();
1048

    
1049
        // get the serialVersion
1050
        try {
1051
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1052
            serialVersion = new Long(serialVersionStr).longValue();
1053
            
1054
        } catch (NullPointerException e) {
1055
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1056
            logMetacat.error(msg);
1057
            throw new InvalidRequest("4883", msg);
1058
            
1059
        }
1060
        result = 
1061
            CNodeService.getInstance(request).setReplicationPolicy(session, identifier, policy, serialVersion);
1062
        response.setStatus(200);
1063
        response.setContentType("text/xml");
1064
        return result;
1065
        
1066
    }
1067
    
1068
    /**
1069
     * Pass the request to set the replication status to CNodeService
1070
     * 
1071
     * @param pid  the identifier of the object to set the replication status on
1072
     * 
1073
     * @throws ServiceFailure
1074
     * @throws NotImplemented
1075
     * @throws InvalidToken
1076
     * @throws NotAuthorized
1077
     * @throws InvalidRequest
1078
     * @throws NotFound
1079
     */
1080
    public boolean setReplicationStatus(String pid) 
1081
        throws ServiceFailure, NotImplemented, InvalidToken, NotAuthorized, 
1082
        InvalidRequest, NotFound {
1083

    
1084
        File tmpDir = getTempDirectory();
1085
        MultipartRequest mr = null;
1086
        boolean result = false;
1087
        Identifier identifier = new Identifier();
1088
        identifier.setValue(pid);
1089
        long serialVersion = 0L;
1090
        String serialVersionStr = null;
1091
        ReplicationStatus status = null;
1092
        String replicationStatus = null;
1093
        NodeReference targetNodeRef = null;
1094
        String targetNode = null;
1095
        
1096
        // Parse the params out of the multipart form data
1097
        // Read the incoming data from its Mime Multipart encoding
1098
        logMetacat.debug("Parsing ReplicaStatus from the mime multipart entity");
1099

    
1100
        // handle MMP inputs
1101
        MultipartRequestResolver mrr = 
1102
            new MultipartRequestResolver(tmpDir.getAbsolutePath(),1000000000, 0);
1103
        
1104
        try {
1105
            mr = mrr.resolveMultipart(request);
1106
            multipartparams = mr.getMultipartParameters();
1107
            logMetacat.debug("Resolved the ReplicaStatus multipart request.");
1108
            
1109
        } catch (IOException e) {
1110
            throw new ServiceFailure("4852", "Couldn't resolve the multipart request: " +
1111
                e.getMessage());
1112
            
1113
        } catch (FileUploadException e) {
1114
            throw new ServiceFailure("4852", "Couldn't resolve the multipart request: " +
1115
                    e.getMessage());
1116
            
1117
        } catch (Exception e) {
1118
            throw new ServiceFailure("4852", "Couldn't resolve the multipart request: " +
1119
                    e.getMessage());
1120
            
1121
        }
1122

    
1123
        // get the serialVersion
1124
        try {
1125
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1126
            serialVersion = new Long(serialVersionStr).longValue();
1127
            
1128
        } catch (NullPointerException e) {
1129
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1130
            logMetacat.error(msg);
1131
            throw new InvalidRequest("4730", msg);
1132
            
1133
        }
1134
        
1135
        // get the replication status param
1136
        try {
1137
            replicationStatus = multipartparams.get("replicationStatus").get(0);
1138
            status = ReplicationStatus.convert(replicationStatus);
1139
        } catch (Exception e) {
1140
            // TODO Auto-generated catch block
1141
            e.printStackTrace();
1142
        }
1143
        
1144
        // get the target node reference param
1145
        targetNode = multipartparams.get("nodeRef").get(0);
1146
        targetNodeRef = new NodeReference();
1147
        targetNodeRef.setValue(targetNode);
1148
        
1149
        result = 
1150
            CNodeService.getInstance(request).setReplicationStatus(session, identifier, targetNodeRef, status, serialVersion);       
1151
        response.setStatus(200);
1152
        response.setContentType("text/xml");
1153
        return result;
1154
        
1155
    }
1156
    
1157
    /**
1158
     * Pass the request to update the replication metadata to CNodeService
1159
     * 
1160
     * @param pid  the identifier of the object to update the replication metadata on
1161
     * 
1162
     * @throws ServiceFailure
1163
     * @throws NotImplemented
1164
     * @throws InvalidToken
1165
     * @throws NotAuthorized
1166
     * @throws InvalidRequest
1167
     * @throws NotFound
1168
     */
1169
    public boolean updateReplicationMetadata(String pid) 
1170
        throws ServiceFailure, NotImplemented, InvalidToken, NotAuthorized, 
1171
        InvalidRequest, NotFound {
1172

    
1173
        boolean result = false;
1174
        long serialVersion = 0L;
1175
        String serialVersionStr = null;
1176
        Replica replica = null;
1177
        Identifier identifier = new Identifier();
1178
        identifier.setValue(pid);
1179

    
1180
        replica = collectReplicaMetadata();
1181
        
1182
        // get the serialVersion
1183
        try {
1184
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1185
            serialVersion = new Long(serialVersionStr).longValue();
1186
            
1187
        } catch (NullPointerException e) {
1188
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1189
            logMetacat.error(msg);
1190
            throw new InvalidRequest("4853", msg);
1191
            
1192
        }
1193

    
1194
        result = 
1195
            CNodeService.getInstance(request).updateReplicationMetadata(session, identifier, replica, serialVersion);
1196
        response.setStatus(200);
1197
        response.setContentType("text/xml");
1198
        return result;
1199

    
1200
    }
1201

    
1202
}
(1-1/9)