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-07 17:16:19 -0700 (Wed, 07 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.TypeMarshaller;
76
import org.jibx.runtime.JiBXException;
77

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

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

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

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

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

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

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

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

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

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

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

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

    
521
        response.setStatus(200);
522

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

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

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

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

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

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

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

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

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

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

    
905
        OutputStream out = response.getOutputStream();
906
        response.setStatus(200);
907
        response.setContentType("text/xml");
908

    
909
        Identifier id = new Identifier();
910
        id.setValue(pid);
911

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

    
944
}
(8-8/11)