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-09-20 11:55:30 -0700 (Tue, 20 Sep 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.text.DateFormat;
32
import java.text.ParseException;
33
import java.text.SimpleDateFormat;
34
import java.util.Date;
35
import java.util.Enumeration;
36
import java.util.Map;
37
import java.util.TimeZone;
38

    
39
import javax.servlet.ServletContext;
40
import javax.servlet.http.HttpServletRequest;
41
import javax.servlet.http.HttpServletResponse;
42

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

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

    
81
/**
82
 * MN REST service implementation handler
83
 * 
84
 * ******************
85
 * MNCore -- DONE
86
 * 		ping() - GET /d1/mn/monitor/ping
87
 * 		log() - GET /d1/mn/log
88
 * 		**getObjectStatistics() - GET /d1/mn/monitor/object
89
 * 		getOperationsStatistics - GET /d1/mn/monitor/event
90
 * 		**getStatus - GET /d1/mn/monitor/status
91
 * 		getCapabilities() - GET /d1/mn/ and /d1/mn/node
92
 * 	
93
 * 	MNRead -- DONE
94
 * 		get() - GET /d1/mn/object/PID
95
 * 		getSystemMetadata() - GET /d1/mn/meta/PID
96
 * 		describe() - HEAD /d1/mn/object/PID
97
 * 		getChecksum() - GET /d1/mn/checksum/PID
98
 * 		listObjects() - GET /d1/mn/object
99
 * 		synchronizationFailed() - POST /d1/mn/error
100
 * 	
101
 * 	MNAuthorization -- DONE
102
 * 		isAuthorized() - GET /d1/mn/isAuthorized/PID
103
 * 		setAccessPolicy() - PUT /d1/mn/accessRules/PID
104
 * 		
105
 * 	MNStorage - DONE
106
 * 		create() - POST /d1/mn/object/PID
107
 * 		update() - PUT /d1/mn/object/PID
108
 * 		delete() - DELETE /d1/mn/object/PID
109
 * 	
110
 * 	MNReplication
111
 * 		replicate() - POST /d1/mn/replicate
112
 * 
113
 * ******************
114
 * @author leinfelder
115
 *
116
 */
117
public class MNResourceHandler extends D1ResourceHandler{
118

    
119
    // MN-specific API Resources
120
    protected static final String RESOURCE_MONITOR = "monitor";
121
    protected static final String RESOURCE_REPLICATE = "replicate";
122
    protected static final String RESOURCE_NODE = "node";
123
    protected static final String RESOURCE_ERROR = "error";
124

    
125
    /**
126
     * Initializes new instance by setting servlet context,request and response
127
     * */
128
    public MNResourceHandler(ServletContext servletContext,
129
            HttpServletRequest request, HttpServletResponse response) {
130
    	super(servletContext, request, response);
131
        logMetacat = Logger.getLogger(MNResourceHandler.class);
132
    }
133

    
134
    /**
135
     * This function is called from REST API servlet and handles each request to the servlet 
136
     * 
137
     * @param httpVerb (GET, POST, PUT or DELETE)
138
     */
139
    @Override
140
    public void handle(byte httpVerb) {
141
    	// prepare the handler
142
    	super.handle(httpVerb);
143
    	
144
        try {
145
        	// get the resource
146
            String resource = request.getPathInfo();
147
            resource = resource.substring(resource.indexOf("/") + 1);
148
            
149
            // default to node info
150
            if (resource.equals("")) {
151
                resource = RESOURCE_NODE;
152
            }
153
            
154
            // get the rest of the path info
155
            String extra = null;
156
            if (resource.lastIndexOf("/") != -1) {
157
                extra = resource.substring(resource.lastIndexOf("/") + 1);
158
            }
159
                        
160
            logMetacat.debug("handling verb " + httpVerb + " request with resource '" + resource + "'");
161
            logMetacat.debug("resource: '" + resource + "'");
162
            boolean status = false;
163
            
164
            if (resource != null) {
165

    
166
                if (resource.startsWith(RESOURCE_NODE)) {
167
                    // node response
168
                    node();
169
                    status = true;
170
                } else if (resource.startsWith(RESOURCE_ACCESS_RULES)) {
171
                    if (httpVerb == POST) {
172
	                	// set the access rules
173
	                    setAccess();
174
	                    status = true;
175
	                    logMetacat.debug("done setting access");
176
                    }
177
                } else if (resource.startsWith(RESOURCE_IS_AUTHORIZED)) {
178
                    if (httpVerb == GET) {
179
	                	// check the access rules
180
	                    isAuthorized(extra);
181
	                    status = true;
182
	                    logMetacat.debug("done getting access");
183
                    }
184
                } else if (resource.startsWith(RESOURCE_META)) {
185
                    logMetacat.debug("Using resource 'meta'");
186
                    // get
187
                    if (httpVerb == GET) {
188
                        getSystemMetadataObject(extra);
189
                        status = true;
190
                    }
191
                    
192
                } else if (resource.startsWith(RESOURCE_OBJECTS)) {
193
                    logMetacat.debug("Using resource 'object'");
194
                    
195
                    logMetacat.debug("objectId: " + extra);
196
                    logMetacat.debug("verb:" + httpVerb);
197

    
198
                    if (httpVerb == GET) {
199
                        getObject(extra);
200
                        status = true;
201
                    } else if (httpVerb == POST) {
202
                        putObject(extra, FUNCTION_NAME_INSERT);
203
                        status = true;
204
                    } else if (httpVerb == PUT) {
205
                        putObject(extra, FUNCTION_NAME_UPDATE);
206
                        status = true;
207
                    } else if (httpVerb == DELETE) {
208
                        deleteObject(extra);
209
                        status = true;
210
                    } else if (httpVerb == HEAD) {
211
                        describeObject(extra);
212
                        status = true;
213
                    }
214
                  
215
                } else if (resource.startsWith(RESOURCE_LOG)) {
216
                    logMetacat.debug("Using resource 'log'");
217
                    // handle log events
218
                    if (httpVerb == GET) {
219
                        getLog();
220
                        status = true;
221
                    }
222
                } else if (resource.startsWith(RESOURCE_CHECKSUM)) {
223
                    logMetacat.debug("Using resource 'checksum'");
224
                    // handle checksum requests
225
                    if (httpVerb == GET) {
226
                        checksum(extra);
227
                        status = true;
228
                    }
229
                } else if (resource.startsWith(RESOURCE_MONITOR)) {
230
                    // there are various parts to monitoring
231
                    if (httpVerb == GET) {
232
                    	// health monitoring calls
233
                        status = monitor(extra);
234
                    }
235
                } else if (resource.startsWith(RESOURCE_REPLICATE)) {
236
                	if (httpVerb == POST) {
237
	                    logMetacat.debug("processing replicate request");
238
	                    replicate();
239
	                    status = true;
240
                	}
241
                } else if (resource.startsWith(RESOURCE_ERROR)) {
242
	                // sync error
243
	                if (httpVerb == POST) {
244
	                    syncError();
245
	                    status = true;
246
	                }
247
                }
248
                
249
                if (!status) {
250
                	throw new ServiceFailure("0000", "Unknown error, status = " + status);
251
                }
252
            } else {
253
            	throw new InvalidRequest("0000", "No resource matched for " + resource);
254
            }
255
        } catch (BaseException be) {
256
        	// report Exceptions as clearly as possible
257
        	OutputStream out = null;
258
			try {
259
				out = response.getOutputStream();
260
			} catch (IOException e) {
261
				logMetacat.error("Could not get output stream from response", e);
262
			}
263
            serializeException(be, out);
264
        } catch (Exception e) {
265
            // report Exceptions as clearly and generically as possible
266
            logMetacat.error(e.getClass() + ": " + e.getMessage(), e);
267
        	OutputStream out = null;
268
			try {
269
				out = response.getOutputStream();
270
			} catch (IOException ioe) {
271
				logMetacat.error("Could not get output stream from response", ioe);
272
			}
273
			ServiceFailure se = new ServiceFailure("0000", e.getMessage());
274
            serializeException(se, out);
275
        }
276
    }
277
    
278
    /**
279
     * Checks the access policy
280
     * @param id
281
     * @return
282
     * @throws ServiceFailure
283
     * @throws InvalidToken
284
     * @throws NotFound
285
     * @throws NotAuthorized
286
     * @throws NotImplemented
287
     * @throws InvalidRequest
288
     */
289
    private boolean isAuthorized(String id) throws ServiceFailure, InvalidToken, NotFound, NotAuthorized, NotImplemented, InvalidRequest {
290
		Identifier pid = new Identifier();
291
		pid.setValue(id);
292
		Permission permission = null;
293
		try {
294
			String perm = params.get("permission")[0];
295
			permission = Permission.convert(perm);
296
		} catch (Exception e) {
297
			logMetacat.warn("No permission specified");
298
		}
299
		boolean result = MNodeService.getInstance().isAuthorized(session, pid, permission);
300
		response.setStatus(200);
301
		response.setContentType("text/xml");
302
		return result;
303
    }
304
    
305
    /**
306
     * Processes failed synchronization message
307
     * @throws NotImplemented
308
     * @throws ServiceFailure
309
     * @throws NotAuthorized
310
     * @throws InvalidRequest
311
     * @throws JiBXException
312
     * @throws IllegalAccessException 
313
     * @throws InstantiationException 
314
     * @throws IOException 
315
     */
316
    private void syncError() throws NotImplemented, ServiceFailure, NotAuthorized, InvalidRequest, JiBXException, IOException, InstantiationException, IllegalAccessException {
317
    	SynchronizationFailed syncFailed = null;
318
    	if (params.containsKey("message")) {
319
            String message = params.get("message")[0];
320
            syncFailed = TypeMarshaller.unmarshalTypeFromStream(SynchronizationFailed.class, new ByteArrayInputStream(message.getBytes("UTF-8")));
321
        }
322
		MNodeService.getInstance().synchronizationFailed(session, syncFailed);
323
    }
324
    
325
    /**
326
     * Handles the monitoring resources
327
     * @return
328
     * @throws NotFound
329
     * @throws ParseException
330
     * @throws NotImplemented
331
     * @throws ServiceFailure
332
     * @throws NotAuthorized
333
     * @throws InvalidRequest
334
     * @throws InsufficientResources
335
     * @throws UnsupportedType
336
     * @throws IOException
337
     * @throws JiBXException
338
     */
339
    private boolean monitor(String pathInfo) 
340
      throws NotFound, ParseException, NotImplemented, ServiceFailure, 
341
      NotAuthorized, InvalidRequest, InsufficientResources, UnsupportedType, 
342
      IOException, JiBXException {
343
    	logMetacat.debug("processing monitor request");
344
        
345
        logMetacat.debug("verb is GET");
346
        logMetacat.debug("pathInfo is " + pathInfo);
347
        
348
        if (pathInfo.toLowerCase().equals("ping")) {
349
            logMetacat.debug("processing ping request");
350
            boolean result = MNodeService.getInstance().ping();
351
            return result;
352
            
353
        } else if (pathInfo.toLowerCase().equals("status")) {
354
            logMetacat.debug("processing status request");
355
            // TODO: implement in MNCore
356
            //MNodeService.getInstance().getStatus();
357
            return false;
358
            
359
        } else if (pathInfo.toLowerCase().equals("object")) {
360
            logMetacat.debug("processing object request");
361
            Identifier pid = null;
362
            ObjectFormat format = null;
363
            if (params.containsKey("format")) {
364
                String f = params.get("format")[0];
365
                format = ObjectFormatCache.getInstance().getFormat(f);
366
            }
367
            if (params.containsKey("pid")) {
368
                String id = params.get("pid")[0];
369
                pid = new Identifier();
370
                pid.setValue(id);
371
            }
372
            
373
            // TODO: implement in MNCore
374
            //ObjectStatistics objectStats = MNodeService.getInstance().getObjectStatistics(format, pid);
375
            return false;
376
            
377
        } else if (pathInfo.toLowerCase().equals("event")) {
378
            logMetacat.debug("processing event request");
379
            ObjectFormatIdentifier fmtid = null;
380
            String fromDateStr = null;
381
            Date fromDate = null;
382
            String toDateStr = null;
383
            Date toDate = null;
384
            String requestor = null;
385
            Subject subject = null;
386
            String eventName = null;
387
            Event event = null;
388

    
389
            if (params.containsKey("formatId")) {
390
                String f = params.get("formatId")[0];
391
                fmtid = ObjectFormatCache.getInstance().getFormat(f).getFmtid();
392
            }
393
            
394
            if (params.containsKey("fromDate")) {
395
                fromDateStr = params.get("fromDate")[0];
396
                fromDate = getDateAsUTC(fromDateStr);
397
            }
398
            
399
            if (params.containsKey("toDate")) {
400
              toDateStr = params.get("toDate")[0];
401
              toDate = getDateAsUTC(toDateStr);
402
            }
403
            
404
            if (params.containsKey("requestor")) {
405
            	requestor = params.get("requestor")[0];
406
            	subject = new Subject();
407
            	subject.setValue(requestor);
408
            }
409
            
410
            if (params.containsKey("event")) {
411
            	eventName = params.get("event")[0];
412
                event = Event.convert(eventName);
413
            }
414
            
415
            MonitorList monitorList = MNodeService.getInstance().getOperationStatistics(session, fromDate, toDate, subject, event, fmtid);
416
            
417
            OutputStream out = response.getOutputStream();
418
            response.setStatus(200);
419
            response.setContentType("text/xml");
420
            
421
            TypeMarshaller.marshalTypeToOutputStream(monitorList, out);
422
            
423
            return true;
424
            
425
        }
426
        
427
        return false;
428
    }
429
    
430
    /*
431
     * Parse an ISO8601 date string, returning a Date in UTC time if the string
432
     * ends in 'Z'.
433
     * 
434
     * @param fromDateStr -  the date string to be parsed
435
     * @return date -  the date object represented by the string
436
     */
437
    private Date getDateAsUTC(String fromDateStr)
438
      throws ParseException {
439

    
440
    	Date date = null;
441
    	
442
    	try {
443
    		// try the expected date format
444
        // a date format for date string arguments
445
        DateFormat dateFormat = 
446
        	new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
447

    
448
	      date = dateFormat.parse(fromDateStr);
449
      
450
    	} catch (ParseException e) {
451
    		// try the date with the UTC indicator
452
        DateFormat utcDateFormat = 
453
        	new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'");
454
        utcDateFormat.setTimeZone(TimeZone.getTimeZone("GMT-0"));
455
        date = utcDateFormat.parse(fromDateStr);
456
        
457
      }
458
    	
459
    	return date;
460
    }
461

    
462
		/**
463
     * Calculate the checksum 
464
     * @throws NotImplemented
465
     * @throws JiBXException
466
     * @throws IOException
467
     * @throws InvalidToken
468
     * @throws ServiceFailure
469
     * @throws NotAuthorized
470
     * @throws NotFound
471
     * @throws InvalidRequest
472
     */
473
    private void checksum(String pid) throws NotImplemented, JiBXException, IOException, InvalidToken, ServiceFailure, NotAuthorized, NotFound, InvalidRequest {
474
    	String checksumAlgorithm = "MD5";
475
        
476
        Identifier pidid = new Identifier();
477
        pidid.setValue(pid);
478
        try {
479
            checksumAlgorithm = params.get("checksumAlgorithm")[0];
480
        } catch(Exception e) {
481
            //do nothing.  default to MD5
482
        	logMetacat.warn("No algorithm specified, using default: " + checksumAlgorithm);
483
        }
484
        logMetacat.debug("getting checksum for object " + pid + " with algorithm " + checksumAlgorithm);
485
        
486
        Checksum c = MNodeService.getInstance().getChecksum(session, pidid, checksumAlgorithm);
487
        logMetacat.debug("got checksum " + c.getValue());
488
        response.setStatus(200);
489
        logMetacat.debug("serializing response");
490
        TypeMarshaller.marshalTypeToOutputStream(c, response.getOutputStream());
491
        logMetacat.debug("done serializing response.");
492
        
493
    }
494
    
495
	/**
496
     * handle the replicate action for MN
497
	 * @throws JiBXException 
498
	 * @throws FileUploadException 
499
	 * @throws IOException 
500
	 * @throws InvalidRequest 
501
	 * @throws ServiceFailure 
502
	 * @throws UnsupportedType 
503
	 * @throws InsufficientResources 
504
	 * @throws NotAuthorized 
505
	 * @throws NotImplemented 
506
	 * @throws IllegalAccessException 
507
	 * @throws InstantiationException 
508
     */
509
    private void replicate() throws ServiceFailure, InvalidRequest, IOException, FileUploadException, JiBXException, NotImplemented, NotAuthorized, InsufficientResources, UnsupportedType, InstantiationException, IllegalAccessException {
510

    
511
        logMetacat.debug("in POST replicate()");
512
        
513
        //parse the systemMetadata
514
        SystemMetadata sysmeta = collectSystemMetadata();
515
        
516
        String sn = multipartparams.get("sourceNode").get(0);
517
        logMetacat.debug("sourceNode: " + sn);
518
        NodeReference sourceNode = TypeMarshaller.unmarshalTypeFromStream(NodeReference.class, new ByteArrayInputStream(sn.getBytes("UTF-8")));
519
        
520
        MNodeService.getInstance().replicate(session, sysmeta, sourceNode);
521

    
522
        response.setStatus(200);
523

    
524
    }
525
    
526
    /**
527
     * Get the Node information
528
     * 
529
     * @throws JiBXException
530
     * @throws IOException
531
     * @throws InvalidRequest 
532
     * @throws ServiceFailure 
533
     * @throws NotAuthorized 
534
     * @throws NotImplemented 
535
     */
536
    private void node() 
537
        throws JiBXException, IOException, NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest {
538
        
539
        Node n = MNodeService.getInstance().getCapabilities();
540
        
541
        NodeList nl = new NodeList();
542
        nl.addNode(n);
543
        
544
        response.setContentType("text/xml");
545
        response.setStatus(200);
546
        TypeMarshaller.marshalTypeToOutputStream(nl, response.getOutputStream());
547
        
548
    }
549
    
550
    /**
551
     * MN_crud.describe()
552
     * http://mule1.dataone.org/ArchitectureDocs/mn_api_crud.html#MN_crud.describe
553
     * @param pid
554
     * @throws InvalidRequest 
555
     * @throws NotImplemented 
556
     * @throws NotFound 
557
     * @throws NotAuthorized 
558
     * @throws ServiceFailure 
559
     * @throws InvalidToken 
560
     */
561
    private void describeObject(String pid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, InvalidRequest
562
    {
563
        response.setStatus(200);
564
        response.setContentType("text/xml");
565
        
566
        Identifier id = new Identifier();
567
        id.setValue(pid);
568

    
569
        DescribeResponse dr = MNodeService.getInstance().describe(session, id);
570
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SZ");
571
        response.addHeader("pid", pid);
572
        response.addHeader("checksum", dr.getDataONE_Checksum().getValue());
573
        response.addHeader("checksum_algorithm", dr.getDataONE_Checksum().getAlgorithm());
574
        response.addHeader("content_length", dr.getContent_Length() + "");
575
        response.addHeader("last_modified", dateFormat.format(dr.getLast_Modified()));
576
        response.addHeader("format", dr.getDataONE_ObjectFormatIdentifier().getValue());
577
       
578
    }
579
    
580
    /**
581
     * get the logs based on passed params.  Available 
582
     * See http://mule1.dataone.org/ArchitectureDocs/mn_api_crud.html#MN_crud.getLogRecords
583
     * for more info
584
     * @throws NotImplemented 
585
     * @throws InvalidRequest 
586
     * @throws NotAuthorized 
587
     * @throws ServiceFailure 
588
     * @throws InvalidToken 
589
     * @throws IOException 
590
     * @throws JiBXException 
591
     */
592
    private void getLog() throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest, NotImplemented, IOException, JiBXException
593
    {
594
            
595
        Date fromDate = null;
596
        Date toDate = null;
597
        Event event = null;
598
        Integer start = null;
599
        Integer count = null;
600
        
601
        try {
602
        	String fromDateS = params.get("fromDate")[0];
603
            logMetacat.debug("param fromDateS: " + fromDateS);
604
            fromDate = DateTimeMarshaller.deserializeDateToUTC(fromDateS);
605
        } catch (Exception e) {
606
        	logMetacat.warn("Could not parse fromDate: " + e.getMessage());
607
        }
608
        try {
609
        	String toDateS = params.get("toDate")[0];
610
            logMetacat.debug("param toDateS: " + toDateS);
611
            toDate = DateTimeMarshaller.deserializeDateToUTC(toDateS);
612
        } catch (Exception e) {
613
        	logMetacat.warn("Could not parse toDate: " + e.getMessage());
614
		}
615
        try {
616
        	String eventS = params.get("event")[0];
617
            event = Event.convert(eventS);
618
        } catch (Exception e) {
619
        	logMetacat.warn("Could not parse event: " + e.getMessage());
620
		}
621
        logMetacat.debug("fromDate: " + fromDate + " toDate: " + toDate);
622
        
623
        try {
624
        	start =  Integer.parseInt(params.get("start")[0]);
625
        } catch (Exception e) {
626
			logMetacat.warn("Could not parse start: " + e.getMessage());
627
		}
628
        try {
629
        	count =  Integer.parseInt(params.get("count")[0]);
630
        } catch (Exception e) {
631
			logMetacat.warn("Could not parse count: " + e.getMessage());
632
		}
633
        
634
        logMetacat.debug("calling getLogRecords");
635
        Log log = MNodeService.getInstance().getLogRecords(session, fromDate, toDate, event, start, count);
636
        
637
        OutputStream out = response.getOutputStream();
638
        response.setStatus(200);
639
        response.setContentType("text/xml");
640
        
641
        TypeMarshaller.marshalTypeToOutputStream(log, out);
642
        
643
    }
644
    
645
    /**
646
     * Implements REST version of DataONE CRUD API --> get
647
     * @param pid ID of data object to be read
648
     * @throws NotImplemented 
649
     * @throws InvalidRequest 
650
     * @throws NotFound 
651
     * @throws NotAuthorized 
652
     * @throws ServiceFailure 
653
     * @throws InvalidToken 
654
     * @throws IOException 
655
     * @throws JiBXException 
656
     */
657
    protected void getObject(String pid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, InvalidRequest, NotImplemented, IOException, JiBXException {
658
        OutputStream out = null;
659
        
660
        if (pid != null) { //get a specific document                
661
            Identifier id = new Identifier();
662
            id.setValue(pid);
663
                
664
            SystemMetadata sm = MNodeService.getInstance().getSystemMetadata(session, id);
665
            
666
            //set the content type
667
            if (sm.getFmtid().getValue().trim().equals(
668
            		ObjectFormatCache.getInstance().getFormat("text/csv").getFmtid().getValue()))
669
            {
670
                response.setContentType("text/csv");
671
                response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".csv");
672
            }
673
            else if (sm.getFmtid().getValue().trim().equals(
674
            		ObjectFormatCache.getInstance().getFormat("text/plain").getFmtid().getValue()))
675
            {
676
                response.setContentType("text/plain");
677
                response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".txt");
678
            } 
679
            else if (sm.getFmtid().getValue().trim().equals(
680
            		ObjectFormatCache.getInstance().getFormat("application/octet-stream").getFmtid().getValue()))
681
            {
682
                response.setContentType("application/octet-stream");
683
            }
684
            else
685
            {
686
                response.setContentType("text/xml");
687
                response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".xml");
688
            }
689
            
690
            InputStream data = MNodeService.getInstance().get(session, id);
691

    
692
            out = response.getOutputStream();  
693
            IOUtils.copyLarge(data, out);
694
            
695
        }
696
        else
697
        { //call listObjects with specified params
698
            Date startTime = null;
699
            Date endTime = null;
700
            ObjectFormat objectFormat = null;
701
            boolean replicaStatus = false;
702
            int start = 0;
703
            //TODO: make the max count into a const
704
            int count = 1000;
705
            Enumeration paramlist = request.getParameterNames();
706
            while (paramlist.hasMoreElements()) 
707
            { //parse the params and make the crud call
708
                String name = (String) paramlist.nextElement();
709
                String[] value = (String[])request.getParameterValues(name);
710

    
711
                if (name.equals("startTime") && value != null)
712
                {
713
                    try
714
                    {
715
                      //startTime = dateFormat.parse(value[0]);
716
                    	startTime = DateTimeMarshaller.deserializeDateToUTC(value[0]);
717
                        //startTime = parseDateAndConvertToGMT(value[0]);
718
                    }
719
                    catch(Exception e)
720
                    {  //if we can't parse it, just don't use the startTime param
721
                        logMetacat.warn("Could not parse startTime: " + value[0]);
722
                        startTime = null;
723
                    }
724
                }
725
                else if(name.equals("endTime") && value != null)
726
                {
727
                    try
728
                    {
729
                      //endTime = dateFormat.parse(value[0]);
730
                    	endTime = DateTimeMarshaller.deserializeDateToUTC(value[0]);
731
                        //endTime = parseDateAndConvertToGMT(value[0]);
732
                    }
733
                    catch(Exception e)
734
                    {  //if we can't parse it, just don't use the endTime param
735
                        logMetacat.warn("Could not parse endTime: " + value[0]);
736
                        endTime = null;
737
                    }
738
                }
739
                else if(name.equals("objectFormat") && value != null) 
740
                {
741
                    objectFormat = ObjectFormatCache.getInstance().getFormat(value[0]);
742
                }
743
                else if(name.equals("replicaStatus") && value != null)
744
                {
745
                    if(value != null && 
746
                       value.length > 0 && 
747
                       (value[0].equals("true") || value[0].equals("TRUE") || value[0].equals("YES")))
748
                    {
749
                        replicaStatus = true;
750
                    }
751
                }
752
                else if(name.equals("start") && value != null)
753
                {
754
                    start = new Integer(value[0]).intValue();
755
                }
756
                else if(name.equals("count") && value != null)
757
                {
758
                    count = new Integer(value[0]).intValue();
759
                }
760
            }
761
            //make the crud call
762
            logMetacat.debug("session: " + session + " startTime: " + startTime +
763
                    " endtime: " + endTime + " objectFormat: " + 
764
                    objectFormat + " replicaStatus: " + replicaStatus + 
765
                    " start: " + start + " count: " + count);
766
           
767
            ObjectFormatIdentifier fmtid = null;
768
           
769
            if ( objectFormat != null ) {
770
          	 fmtid = objectFormat.getFmtid();
771
          	 
772
            }
773
            ObjectList ol = 
774
           	 MNodeService.getInstance().listObjects(session, startTime, endTime, 
775
               fmtid, replicaStatus, start, count);
776
           
777
            out = response.getOutputStream();  
778
            response.setStatus(200);
779
            response.setContentType("text/xml");
780
            // Serialize and write it to the output stream
781
            TypeMarshaller.marshalTypeToOutputStream(ol, out);
782
            
783
        }
784
        
785
    }
786
    
787

    
788
    /**
789
     * Retrieve System Metadata
790
     * @param pid
791
     * @throws InvalidToken
792
     * @throws ServiceFailure
793
     * @throws NotAuthorized
794
     * @throws NotFound
795
     * @throws InvalidRequest
796
     * @throws NotImplemented
797
     * @throws IOException
798
     * @throws JiBXException
799
     */
800
    protected void getSystemMetadataObject(String pid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, InvalidRequest, NotImplemented, IOException, JiBXException {
801

    
802
        Identifier id = new Identifier();
803
        id.setValue(pid);
804
        SystemMetadata sysmeta = MNodeService.getInstance().getSystemMetadata(session, id);
805
        
806
        response.setContentType("text/xml");
807
        response.setStatus(200);
808
        OutputStream out = response.getOutputStream();
809
        
810
        // Serialize and write it to the output stream
811
        TypeMarshaller.marshalTypeToOutputStream(sysmeta, out);
812
   }
813
    
814
    
815
    /**
816
     * Inserts or updates the object
817
     * 
818
     * @param pid - ID of data object to be inserted or updated.  If action is update, the pid
819
     *               is the existing pid.  If insert, the pid is the new one
820
     * @throws InvalidRequest 
821
     * @throws ServiceFailure 
822
     * @throws JiBXException 
823
     * @throws NotImplemented 
824
     * @throws InvalidSystemMetadata 
825
     * @throws InsufficientResources 
826
     * @throws UnsupportedType 
827
     * @throws IdentifierNotUnique 
828
     * @throws NotAuthorized 
829
     * @throws InvalidToken 
830
     * @throws NotFound 
831
     * @throws IOException 
832
     * @throws IllegalAccessException 
833
     * @throws InstantiationException 
834
     */
835
    protected void putObject(String pid, String action) throws ServiceFailure, InvalidRequest, JiBXException, InvalidToken, NotAuthorized, IdentifierNotUnique, UnsupportedType, InsufficientResources, InvalidSystemMetadata, NotImplemented, NotFound, IOException, InstantiationException, IllegalAccessException {
836
        logMetacat.debug("putObject with pid " + pid);
837
        logMetacat.debug("Entering putObject: " + pid + "/" + action);
838
        
839
        response.setStatus(200);
840
        response.setContentType("text/xml");
841
        OutputStream out = response.getOutputStream();
842
        
843
        // Read the incoming data from its Mime Multipart encoding
844
    	Map<String, File> files = collectMultipartFiles();
845
        InputStream object = null;
846
        InputStream sysmeta = null;
847

    
848
        File smFile = files.get("sysmeta");
849
        sysmeta = new FileInputStream(smFile);
850
        File objFile = files.get("object");
851
        object = new FileInputStream(objFile);
852
        
853
        if (action.equals(FUNCTION_NAME_INSERT)) { 
854
            // handle inserts
855
            logMetacat.debug("Commence creation...");
856
            SystemMetadata smd = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysmeta);
857

    
858
            Identifier id = new Identifier();
859
            id.setValue(pid);
860
            logMetacat.debug("creating object with pid " + pid);
861
            Identifier rId = MNodeService.getInstance().create(session, id, object, smd);
862
            TypeMarshaller.marshalTypeToOutputStream(rId, out);
863
            
864
        } else if (action.equals(FUNCTION_NAME_UPDATE)) {
865
        	// handle updates
866
        	
867
            // construct pids
868
            Identifier newPid = new Identifier();
869
            try {
870
            	String newPidString = multipartparams.get("newPid").get(0);
871
                newPid.setValue(newPidString);
872
            } catch (Exception e) {
873
				logMetacat.warn("newPid not given");
874
			}
875
            
876
            Identifier obsoletedPid = new Identifier();
877
            obsoletedPid.setValue(pid);
878
           
879
            logMetacat.debug("Commence update...");
880
            
881
            // get the systemmetadata object
882
            SystemMetadata smd = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysmeta);
883

    
884
            Identifier rId = MNodeService.getInstance().update(session, newPid, object, obsoletedPid, smd);
885
            TypeMarshaller.marshalTypeToOutputStream(rId, out);
886
        } else {
887
            throw new InvalidRequest("1000", "Operation must be create or update.");
888
        }
889
            
890
            
891
    }
892

    
893
    /**
894
     * Handle delete 
895
     * @param pid ID of data object to be deleted
896
     * @throws IOException
897
     * @throws InvalidRequest 
898
     * @throws NotImplemented 
899
     * @throws NotFound 
900
     * @throws NotAuthorized 
901
     * @throws ServiceFailure 
902
     * @throws InvalidToken 
903
     * @throws JiBXException 
904
     */
905
    private void deleteObject(String pid) throws IOException, InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, InvalidRequest, JiBXException 
906
    {
907

    
908
        OutputStream out = response.getOutputStream();
909
        response.setStatus(200);
910
        response.setContentType("text/xml");
911

    
912
        Identifier id = new Identifier();
913
        id.setValue(pid);
914

    
915
        logMetacat.debug("Calling delete");
916
        MNodeService.getInstance().delete(session, id);
917
        TypeMarshaller.marshalTypeToOutputStream(id, out);
918
        
919
    }    
920
    
921
    /**
922
     * set the access perms on a document
923
     * @throws JiBXException 
924
     * @throws InvalidRequest 
925
     * @throws NotImplemented 
926
     * @throws NotAuthorized 
927
     * @throws NotFound 
928
     * @throws ServiceFailure 
929
     * @throws InvalidToken 
930
     * @throws IllegalAccessException 
931
     * @throws InstantiationException 
932
     * @throws IOException 
933
     */
934
    protected void setAccess() throws JiBXException, InvalidToken, ServiceFailure, NotFound, NotAuthorized, NotImplemented, InvalidRequest, IOException, InstantiationException, IllegalAccessException
935
    {
936
    
937
        String pid = params.get("pid")[0];
938
        Identifier id = new Identifier();
939
        id.setValue(pid);
940
        String accesspolicy = params.get("accesspolicy")[0];
941
        AccessPolicy accessPolicy = TypeMarshaller.unmarshalTypeFromStream(AccessPolicy.class, new ByteArrayInputStream(accesspolicy.getBytes("UTF-8")));
942
        MNodeService.getInstance().setAccessPolicy(session, id, accessPolicy);
943
        
944
        
945
    }
946

    
947
}
(8-8/11)