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-06-30 15:54:03 -0700 (Thu, 30 Jun 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.FileNotFoundException;
29
import java.io.IOException;
30
import java.io.InputStream;
31
import java.io.OutputStream;
32
import java.io.PrintWriter;
33
import java.io.StringReader;
34
import java.io.UnsupportedEncodingException;
35
import java.text.DateFormat;
36
import java.text.ParseException;
37
import java.text.SimpleDateFormat;
38
import java.util.Date;
39
import java.util.Enumeration;
40
import java.util.Hashtable;
41
import java.util.Iterator;
42
import java.util.List;
43
import java.util.Map;
44
import java.util.Timer;
45

    
46
import javax.servlet.ServletContext;
47
import javax.servlet.http.HttpServletRequest;
48
import javax.servlet.http.HttpServletResponse;
49

    
50
import org.apache.commons.io.IOUtils;
51
import org.apache.log4j.Logger;
52
import org.dataone.client.ObjectFormatCache;
53
import org.dataone.client.auth.CertificateManager;
54
import org.dataone.mimemultipart.MultipartRequest;
55
import org.dataone.mimemultipart.MultipartRequestResolver;
56
import org.dataone.service.exceptions.BaseException;
57
import org.dataone.service.exceptions.IdentifierNotUnique;
58
import org.dataone.service.exceptions.InsufficientResources;
59
import org.dataone.service.exceptions.InvalidRequest;
60
import org.dataone.service.exceptions.InvalidSystemMetadata;
61
import org.dataone.service.exceptions.InvalidToken;
62
import org.dataone.service.exceptions.NotAuthorized;
63
import org.dataone.service.exceptions.NotFound;
64
import org.dataone.service.exceptions.NotImplemented;
65
import org.dataone.service.exceptions.ServiceFailure;
66
import org.dataone.service.exceptions.SynchronizationFailed;
67
import org.dataone.service.exceptions.UnsupportedType;
68
import org.dataone.service.types.AccessPolicy;
69
import org.dataone.service.types.Checksum;
70
import org.dataone.service.types.DescribeResponse;
71
import org.dataone.service.types.Event;
72
import org.dataone.service.types.Identifier;
73
import org.dataone.service.types.Log;
74
import org.dataone.service.types.MonitorList;
75
import org.dataone.service.types.Node;
76
import org.dataone.service.types.NodeList;
77
import org.dataone.service.types.NodeReference;
78
import org.dataone.service.types.ObjectFormat;
79
import org.dataone.service.types.ObjectList;
80
import org.dataone.service.types.Permission;
81
import org.dataone.service.types.Subject;
82
import org.dataone.service.types.SystemMetadata;
83
import org.jibx.runtime.JiBXException;
84

    
85
import edu.ucsb.nceas.metacat.MetacatHandler;
86
import edu.ucsb.nceas.metacat.dataone.MNodeService;
87

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

    
126
    // MN-specific API Resources
127
    protected static final String RESOURCE_MONITOR = "monitor";
128
    protected static final String RESOURCE_REPLICATE = "replicate";
129
    protected static final String RESOURCE_NODE = "node";
130
    protected static final String RESOURCE_ERROR = "error";
131

    
132

    
133
    /**
134
     * Initializes new instance by setting servlet context,request and response
135
     * */
136
    public MNResourceHandler(ServletContext servletContext,
137
            HttpServletRequest request, HttpServletResponse response) {
138
    	super(servletContext, request, response);
139
        logMetacat = Logger.getLogger(MNResourceHandler.class);
140
    }
141

    
142
    /**
143
     * This function is called from REST APU servlet and handles each request to the servlet 
144
     * 
145
     * @param httpVerb (GET, POST, PUT or DELETE)
146
     */
147
    public void handle(byte httpVerb) {
148
        logMetacat = Logger.getLogger(MNResourceHandler.class);
149
        try {
150
            String resourcePrefix = RESOURCE_BASE_URL + "/mn/";
151
        	String resource = request.getServletPath();
152
            
153
            if (resource.endsWith(resourcePrefix)) {
154
                resource = RESOURCE_NODE;
155
            }
156
            else {
157
            	// remove prefix
158
                resource = resource.substring(resource.indexOf(resourcePrefix) + resourcePrefix.length());
159
                resource = resource.trim();
160
            }
161
                        
162
            System.out.println("handling verb " + httpVerb + " request with resource '" + resource + "'");
163
            System.out.println("resource: '" + resource + "'");
164
            boolean status = false;
165

    
166
            // load session from certificate in request
167
            session = CertificateManager.getInstance().getSession(request);
168
            
169
            if (resource != null) {
170
                //resource = request.getServletPath().substring(1);
171

    
172
                params = new Hashtable<String, String[]>();
173
                initParams();
174

    
175
                Timer timer = new Timer();
176
                handler = new MetacatHandler(timer);
177

    
178
                if (resource.equals(RESOURCE_NODE)) {
179
                    // node response
180
                    node();
181
                    status = true;
182
                    
183
                } else if (resource.equals(RESOURCE_ACCESS_RULES)) {
184
                    if (httpVerb == POST) {
185
	                	// set the access rules
186
	                    setaccess();
187
	                    status = true;
188
	                    System.out.println("done setting access");
189
                    }
190
                } else if (resource.equals(RESOURCE_IS_AUTHORIZED)) {
191
                    if (httpVerb == GET) {
192
	                	// check the access rules
193
                    	String objectId = request.getPathInfo();
194
                        if (objectId != null && objectId.length() > 1) {
195
                            objectId = request.getPathInfo().substring(1);
196
                        }
197
	                    isAuthorized(objectId);
198
	                    status = true;
199
	                    System.out.println("done getting access");
200
                    }
201
                } else if (resource.equals(RESOURCE_META)) {
202
                    System.out.println("Using resource 'meta'");
203
                    String objectId = request.getPathInfo();
204
                    if (objectId != null && objectId.length() > 1) {
205
                        objectId = request.getPathInfo().substring(1);
206
                    }
207
                    
208
                    // get
209
                    if (httpVerb == GET) {
210
                        getSystemMetadataObject(objectId);
211
                        status = true;
212
                    }
213
                    
214
                } else if (resource.equals(RESOURCE_OBJECTS)) {
215
                    System.out.println("Using resource 'object'");
216

    
217
                    String objectId = request.getPathInfo();
218
                    if (objectId != null && objectId.length() > 1) {
219
                        objectId = request.getPathInfo().substring(1);
220
                    } else {
221
                        objectId = null;
222
                    }
223
                    
224
                    System.out.println("objectId: " + objectId);
225
                    logMetacat.debug("verb:" + httpVerb);
226

    
227
                    if (httpVerb == GET) {
228
                        getObject(objectId);
229
                        status = true;
230
                    } else if (httpVerb == POST) {
231
                        putObject(objectId, FUNCTION_NAME_INSERT);
232
                        status = true;
233
                    } else if (httpVerb == PUT) {
234
                        putObject(objectId, FUNCTION_NAME_UPDATE);
235
                        status = true;
236
                    } else if (httpVerb == DELETE) {
237
                        deleteObject(objectId);
238
                        status = true;
239
                    } else if (httpVerb == HEAD) {
240
                        describeObject(objectId);
241
                        status = true;
242
                    }
243
                  
244
                } else if (resource.equals(RESOURCE_LOG)) {
245
                    System.out.println("Using resource 'log'");
246
                    // handle log events
247
                    if (httpVerb == GET) {
248
                        getLog();
249
                        status = true;
250
                    }
251
                } else if (resource.equals(RESOURCE_CHECKSUM)) {
252
                    System.out.println("Using resource 'checksum'");
253
                    // handle checksum requests
254
                    if (httpVerb == GET) {
255
                        checksum();
256
                        status = true;
257
                    }
258
                } else if (resource.startsWith(RESOURCE_MONITOR)) {
259
                    // there are various parts to monitoring
260
                    if (httpVerb == GET) {
261
                    	// health monitoring calls
262
                        monitor();
263
                    }
264
                    status = true;
265
                } else if (resource.equals(RESOURCE_REPLICATE)) {
266
                	if (httpVerb == POST) {
267
	                    System.out.println("processing replicate request");
268
	                    replicate();
269
	                    status = true;
270
                	}
271
                } else if (resource.equals(RESOURCE_ERROR)) {
272
	                // sync error
273
	                if (httpVerb == POST) {
274
	                    syncError();
275
	                    status = true;
276
	                }
277
                }
278
                
279
                if (!status) {
280
                    response.setStatus(400);
281
                    printError("Incorrect parameters!", response);
282
                }
283
            } else {
284
                response.setStatus(400);
285
                printError("Incorrect resource!", response);
286
            }
287
        } catch (BaseException be) {
288
        	// report Exceptions as clearly as possible
289
        	OutputStream out = null;
290
			try {
291
				out = response.getOutputStream();
292
			} catch (IOException e) {
293
				logMetacat.error("Could not get output stream from response", e);
294
			}
295
            serializeException(be, out);
296
        } catch (Exception e) {
297
            logMetacat.error(e.getClass() + ": " + e.getMessage());
298
            System.out.println("Error handle(): " + e.getClass() + ": " + e.getMessage());
299
            e.printStackTrace();
300
        }
301
    }
302
    
303
    private boolean isAuthorized(String id) throws ServiceFailure, InvalidToken, NotFound, NotAuthorized, NotImplemented, InvalidRequest {
304
		Identifier pid = new Identifier();
305
		pid.setValue(id);
306
		Permission permission = null;
307
		try {
308
			String perm = params.get("permission")[0];
309
			permission = Permission.valueOf(perm);
310
		} catch (Exception e) {
311
			logMetacat.warn("No permission specified");
312
		}
313
		boolean result = MNodeService.getInstance().isAuthorized(session, pid, permission);
314
		response.setStatus(200);
315
		response.setContentType("text/xml");
316
		return result;
317
    }
318
    
319
    private void syncError() throws NotImplemented, ServiceFailure, NotAuthorized, InvalidRequest, UnsupportedEncodingException, JiBXException {
320
    	SynchronizationFailed syncFailed = null;
321
    	if (params.containsKey("message")) {
322
            String message = params.get("message")[0];
323
            syncFailed = (SynchronizationFailed) deserializeServiceType(SynchronizationFailed.class, new ByteArrayInputStream(message.getBytes("UTF-8")));
324
        }
325
		MNodeService.getInstance().synchronizationFailed(session, syncFailed);
326
    }
327
    
328
    private boolean monitor() throws NotFound, ParseException, NotImplemented, ServiceFailure, NotAuthorized, InvalidRequest, InsufficientResources, UnsupportedType, IOException, JiBXException {
329
    	System.out.println("processing monitor request");
330
        String pathInfo = request.getPathInfo();
331
        
332
        System.out.println("verb is GET");
333
        System.out.println("pathInfo is " + pathInfo);
334
        pathInfo = pathInfo.substring(1);
335
        
336
        if (pathInfo.toLowerCase().equals("ping")) {
337
            System.out.println("processing ping request");
338
            boolean result = MNodeService.getInstance().ping();
339
            return result;
340
            
341
        } else if (pathInfo.toLowerCase().equals("status")) {
342
            System.out.println("processing status request");
343
            // TODO: implement in MNCore
344
            //MNodeService.getInstance().getStatus();
345
            return false;
346
            
347
        } else if (pathInfo.toLowerCase().equals("object")) {
348
            System.out.println("processing object request");
349
            Identifier pid = null;
350
            ObjectFormat format = null;
351
            if (params.containsKey("format")) {
352
                String f = params.get("format")[0];
353
                format = ObjectFormatCache.getInstance().getFormat(f);
354
            }
355
            if (params.containsKey("pid")) {
356
                String id = params.get("pid")[0];
357
                pid = new Identifier();
358
                pid.setValue(id);
359
            }
360
            
361
            // TODO: implement in MNCore
362
            //ObjectStatistics objectStats = MNodeService.getInstance().getObjectStatistics(format, pid);
363
            
364
        } else if (pathInfo.toLowerCase().equals("event")) {
365
            System.out.println("processing event request");
366
            ObjectFormat format = null;
367
            Integer period = null;
368
            String requestor = null;
369
            Subject subject = null;
370
            String eventName = null;
371
            Event event = null;
372

    
373
            if (params.containsKey("format")) {
374
                String f = params.get("format")[0];
375
                format = ObjectFormatCache.getInstance().getFormat(f);
376
            }
377
            if (params.containsKey("period")) {
378
                String t = params.get("period")[0];
379
                period = Integer.valueOf(t);
380
            }
381
            if (params.containsKey("requestor")) {
382
            	requestor = params.get("requestor")[0];
383
            	subject = new Subject();
384
            	subject.setValue(requestor);
385
            }
386
            if (params.containsKey("event")) {
387
            	eventName = params.get("event")[0];
388
                event = Event.valueOf(eventName);
389
            }
390
            
391
            MonitorList monitorList = MNodeService.getInstance().getOperationStatistics(session, period, subject, event, format);
392
            
393
            OutputStream out = response.getOutputStream();
394
            response.setStatus(200);
395
            response.setContentType("text/xml");
396
            
397
            serializeServiceType(MonitorList.class, monitorList, out);
398
            
399
        }
400
        
401
        return true;
402
    }
403
    
404
    private void checksum() throws NotImplemented, JiBXException, IOException {
405
    	String checksumAlgorithm = "MD5";
406
        String guid = request.getPathInfo();
407
        if (guid != null && guid.length() > 1) {
408
            guid = request.getPathInfo().substring(1); // trim the slash
409
        }
410
        Identifier guidid = new Identifier();
411
        guidid.setValue(guid);
412
        try {
413
            checksumAlgorithm = params.get("checksumAlgorithm")[0];
414
        } catch(Exception e) {
415
            //do nothing.  default to MD5
416
        	logMetacat.warn("No algorithm specified, using default: " + checksumAlgorithm);
417
        }
418
        System.out.println("getting checksum for object " + guid + " with algorithm " + checksumAlgorithm);
419
        try {
420
            Checksum c = MNodeService.getInstance().getChecksum(session, guidid, checksumAlgorithm);
421
            System.out.println("got checksum " + c.getValue());
422
            response.setStatus(200);
423
            System.out.println("serializing response");
424
            serializeServiceType(Checksum.class, c, response.getOutputStream());
425
            System.out.println("done serializing response.");
426
        }
427
        catch(NotAuthorized na)
428
        {
429
            na.setDetail_code("1400");
430
            serializeException(na, response.getOutputStream());
431
        }
432
        catch(NotFound nf)
433
        {
434
            nf.setDetail_code("1420");
435
            serializeException(nf, response.getOutputStream());
436
        }
437
        catch(InvalidRequest ir)
438
        {
439
            ir.setDetail_code("1402");
440
            serializeException(ir, response.getOutputStream());
441
        }
442
        catch(ServiceFailure sf)
443
        {
444
            sf.setDetail_code("1410");
445
            serializeException(sf, response.getOutputStream());
446
        }
447
        catch(InvalidToken it)
448
        {
449
            it.setDetail_code("1430");
450
            serializeException(it, response.getOutputStream());
451
        }
452
    }
453
    
454
	/**
455
     * handle the replicate action for MN
456
	 * @throws Exception 
457
     */
458
    private void replicate() throws Exception {
459

    
460
        System.out.println("in POST replicate()");
461

    
462
        File tmpDir = getTempDirectory();
463
        System.out.println("temp dir: " + tmpDir.getAbsolutePath());
464
        MultipartRequestResolver mrr = new MultipartRequestResolver(
465
                tmpDir.getAbsolutePath(), 1000000000, 0);
466
        MultipartRequest mr = mrr.resolveMultipart(request);
467
        Map<String, File> files = mr.getMultipartFiles();
468
        Iterator keys = files.keySet().iterator();
469
        while(keys.hasNext()) {
470
            String key = (String)keys.next();
471
            System.out.println("files key: " + key);
472
            System.out.println("files value: " + files.get(key));
473
        }
474
        
475
        Map<String, List<String>> params = mr.getMultipartParameters();
476
        keys = params.keySet().iterator();
477
        while(keys.hasNext()) {
478
            String key = (String)keys.next();
479
            System.out.println("params key: " + key);
480
            System.out.println("params value: " + params.get(key));
481
        }
482
        
483
        // File f = files.get("sysmeta");
484
        // the files are not being keyed by the part name, but rather the filename
485
        File f = files.get(files.keySet().iterator().next());
486
        
487
        System.out.println("file: " + f.getAbsolutePath());
488
        FileInputStream fis = new FileInputStream(f);
489

    
490
        String sn = params.get("sourceNode").get(0);
491
        System.out.println("sourceNode: " + sn);
492
        NodeReference sourceNode = (NodeReference) deserializeServiceType(NodeReference.class, new ByteArrayInputStream(sn.getBytes("UTF-8")));
493
        
494
        //parse the systemMetadata
495
        SystemMetadata sysmeta = (SystemMetadata) deserializeServiceType(SystemMetadata.class, fis);
496

    
497
        MNodeService.getInstance().replicate(session, sysmeta, sourceNode);
498

    
499
        response.setStatus(200);
500

    
501
    }
502
    
503
    /**
504
     * Get the Node information
505
     * 
506
     * @throws JiBXException
507
     * @throws IOException
508
     * @throws InvalidRequest 
509
     * @throws ServiceFailure 
510
     * @throws NotAuthorized 
511
     * @throws NotImplemented 
512
     */
513
    private void node() 
514
        throws JiBXException, IOException, NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest {
515
        
516
        Node n = MNodeService.getInstance().getCapabilities();
517
        
518
        NodeList nl = new NodeList();
519
        nl.addNode(n);
520
        
521
        response.setContentType("text/xml");
522
        response.setStatus(200);
523
        serializeServiceType(NodeList.class, nl, response.getOutputStream());
524
        
525
    }
526
    
527
    /**
528
     * MN_crud.describe()
529
     * http://mule1.dataone.org/ArchitectureDocs/mn_api_crud.html#MN_crud.describe
530
     * @param guid
531
     */
532
    private void describeObject(String guid)
533
    {
534
        Logger logMetacat = Logger.getLogger(MNResourceHandler.class);
535
        OutputStream out = null;
536
        try
537
        {
538
            out = response.getOutputStream();
539
        }
540
        catch(Exception e)
541
        {
542
            logMetacat.error("Error getting output stream in describeObject: " + e.getClass() + ": " + e.getMessage());
543
            return;
544
        }
545
        response.setStatus(200);
546
        response.setContentType("text/xml");
547
        Identifier id = new Identifier();
548
        id.setValue(guid);
549
        try
550
        {
551
            DescribeResponse dr = MNodeService.getInstance().describe(session, id);
552
            DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SZ");
553
            response.addHeader("guid", guid);
554
            response.addHeader("checksum", dr.getDataONE_Checksum().getValue());
555
            response.addHeader("checksum_algorithm", dr.getDataONE_Checksum().getAlgorithm().name());
556
            response.addHeader("content_length", dr.getContent_Length() + "");
557
            response.addHeader("last_modified", dateFormat.format(dr.getLast_Modified()));
558
            response.addHeader("format", dr.getDataONE_ObjectFormat().toString());
559
        }
560
        catch(InvalidRequest ir)
561
        {
562
            serializeException(ir, out);
563
        }
564
        catch(NotImplemented ni)
565
        {
566
            serializeException(ni, out);
567
        }
568
        catch(NotAuthorized na)
569
        {
570
            serializeException(na, out);
571
        }
572
        catch(ServiceFailure sf)
573
        {
574
            serializeException(sf, out);
575
        }
576
        catch(NotFound nf)
577
        {
578
            serializeException(nf, out);
579
        }
580
        catch(InvalidToken it)
581
        {
582
            serializeException(it, out);
583
        }
584
    }
585
    
586
    /**
587
     * get the logs based on passed params.  Available 
588
     * See http://mule1.dataone.org/ArchitectureDocs/mn_api_crud.html#MN_crud.getLogRecords
589
     * for more info
590
     */
591
    private void getLog()
592
    {
593
        OutputStream out = null;
594
        try {
595
            
596
            Date fromDate = null;
597
            Date toDate = null;
598
            Event event = null;
599
            Integer start = null;
600
            Integer count = null;
601
            
602
            try {
603
            	String fromDateS = params.get("fromDate")[0];
604
                System.out.println("param fromDateS: " + fromDateS);
605
                fromDate = parseDateAndConvertToGMT(fromDateS);
606
            } catch (Exception e) {
607
            	logMetacat.warn("Could not parse fromDate: " + e.getMessage());
608
            }
609
            try {
610
            	String toDateS = params.get("toDate")[0];
611
                System.out.println("param toDateS: " + toDateS);
612
                toDate = parseDateAndConvertToGMT(toDateS);
613
            } catch (Exception e) {
614
            	logMetacat.warn("Could not parse toDate: " + e.getMessage());
615
			}
616
            try {
617
            	String eventS = params.get("event")[0];
618
                event = Event.convert(eventS);
619
            } catch (Exception e) {
620
            	logMetacat.warn("Could not parse event: " + e.getMessage());
621
			}
622
            System.out.println("fromDate: " + fromDate + " toDate: " + toDate);
623
            
624
            try {
625
            	start =  Integer.parseInt(params.get("start")[0]);
626
            } catch (Exception e) {
627
				logMetacat.warn("Could not parse start: " + e.getMessage());
628
			}
629
            try {
630
            	count =  Integer.parseInt(params.get("count")[0]);
631
            } catch (Exception e) {
632
				logMetacat.warn("Could not parse count: " + e.getMessage());
633
			}
634
            
635
            System.out.println("calling getLogRecords");
636
            Log log = MNodeService.getInstance().getLogRecords(session, fromDate, toDate, event, start, count);
637
            
638
            out = response.getOutputStream();
639
            response.setStatus(200);
640
            response.setContentType("text/xml");
641
            
642
            serializeServiceType(Log.class, log, out);
643
        }
644
        catch(Exception e) {
645
            String msg = "Could not get logs: " + e.getClass() + ": " + e.getMessage();
646
            response.setStatus(500);
647
            ServiceFailure sf = new ServiceFailure("1490", msg);
648
            logMetacat.error(msg);
649
            e.printStackTrace();
650
            serializeException(sf, out);
651
        }
652
    }
653
    
654
    /**
655
     * Implements REST version of DataONE CRUD API --> get
656
     * @param guid ID of data object to be read
657
     */
658
    protected void getObject(String guid) {
659
        OutputStream out = null;
660
        try {
661
            out = response.getOutputStream();
662
            response.setStatus(200);
663
            
664
            if(guid != null)
665
            { //get a specific document                
666
                Identifier id = new Identifier();
667
                id.setValue(guid);
668
                try
669
                {
670
                    
671
                    SystemMetadata sm = MNodeService.getInstance().getSystemMetadata(session, id);
672
                    
673
                    //set the content type
674
                    if(sm.getObjectFormat().getFmtid().getValue().trim().equals(
675
                    		ObjectFormatCache.getInstance().getFormat("text/csv").getFmtid().getValue()))
676
                    {
677
                        response.setContentType("text/csv");
678
                        response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".csv");
679
                    }
680
                    else if(sm.getObjectFormat().getFmtid().getValue().trim().equals(
681
                    		ObjectFormatCache.getInstance().getFormat("text/plain").getFmtid().getValue()))
682
                    {
683
                        response.setContentType("text/plain");
684
                        response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".txt");
685
                    } 
686
                    else if(sm.getObjectFormat().getFmtid().getValue().trim().equals(
687
                    		ObjectFormatCache.getInstance().getFormat("application/octet-stream").getFmtid().getValue()))
688
                    {
689
                        response.setContentType("application/octet-stream");
690
                    }
691
                    else
692
                    {
693
                        response.setContentType("text/xml");
694
                        response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".xml");
695
                    }
696
                    
697
                    InputStream data = MNodeService.getInstance().get(session, id);
698
                    IOUtils.copyLarge(data, response.getOutputStream());
699
                }
700
                catch(InvalidToken it)
701
                {
702
                    response.setStatus(500);
703
                    serializeException(it, out); 
704
                }
705
                catch(ServiceFailure sf)
706
                {
707
                    response.setStatus(500);
708
                    serializeException(sf, out); 
709
                }
710
                catch(NotAuthorized na)
711
                {
712
                    response.setStatus(500);
713
                    serializeException(na, out); 
714
                }
715
                catch(NotFound nf)
716
                {
717
                    response.setStatus(500);
718
                    serializeException(nf, out); 
719
                }
720
                catch(NotImplemented ni)
721
                {
722
                    response.setStatus(500);
723
                    serializeException(ni, out); 
724
                }
725
                catch(Exception e)
726
                {
727
                    response.setStatus(500);
728
                    System.out.println("Error with Crud.get().  " +
729
                            "If this is an 'Exception producing data' error, " +
730
                            "go to CrudService.get() for better debugging.  " +
731
                            "Here's the error: " + e.getClass() + ": " + e.getMessage());
732
                    e.printStackTrace();
733
                    ServiceFailure sf = new ServiceFailure("1030", 
734
                            "IO Error in getObject: " + e.getClass() + ": " + e.getMessage());
735
                    serializeException(sf, out); 
736
                }
737
            }
738
            else
739
            { //call listObjects with specified params
740
                Date startTime = null;
741
                Date endTime = null;
742
                ObjectFormat objectFormat = null;
743
                boolean replicaStatus = false;
744
                int start = 0;
745
                //TODO: make the max count into a const
746
                int count = 1000;
747
                Enumeration paramlist = request.getParameterNames();
748
                while (paramlist.hasMoreElements()) 
749
                { //parse the params and make the crud call
750
                    String name = (String) paramlist.nextElement();
751
                    String[] value = (String[])request.getParameterValues(name);
752
                    /*for(int i=0; i<value.length; i++)
753
                    {
754
                        System.out.println("name: " + name + " value: " + value[i]);
755
                    }*/
756
                    if(name.equals("startTime") && value != null)
757
                    {
758
                        try
759
                        {
760
                          //startTime = dateFormat.parse(value[0]);
761
                            startTime = parseDateAndConvertToGMT(value[0]);
762
                        }
763
                        catch(Exception e)
764
                        {  //if we can't parse it, just don't use the startTime param
765
                            System.out.println("Could not parse startTime: " + value[0]);
766
                            startTime = null;
767
                        }
768
                    }
769
                    else if(name.equals("endTime") && value != null)
770
                    {
771
                        try
772
                        {
773
                          //endTime = dateFormat.parse(value[0]);
774
                            endTime = parseDateAndConvertToGMT(value[0]);
775
                        }
776
                        catch(Exception e)
777
                        {  //if we can't parse it, just don't use the endTime param
778
                            System.out.println("Could not parse endTime: " + value[0]);
779
                            endTime = null;
780
                        }
781
                    }
782
                    else if(name.equals("objectFormat") && value != null) 
783
                    {
784
                        objectFormat = ObjectFormatCache.getInstance().getFormat(value[0]);
785
                    }
786
                    else if(name.equals("replicaStatus") && value != null)
787
                    {
788
                        if(value != null && 
789
                           value.length > 0 && 
790
                           (value[0].equals("true") || value[0].equals("TRUE") || value[0].equals("YES")))
791
                        {
792
                            replicaStatus = true;
793
                        }
794
                    }
795
                    else if(name.equals("start") && value != null)
796
                    {
797
                        start = new Integer(value[0]).intValue();
798
                    }
799
                    else if(name.equals("count") && value != null)
800
                    {
801
                        count = new Integer(value[0]).intValue();
802
                    }
803
                }
804
                //make the crud call
805
                System.out.println("session: " + session + " startTime: " + startTime +
806
                        " endtime: " + endTime + " objectFormat: " + 
807
                        objectFormat + " replicaStatus: " + replicaStatus + 
808
                        " start: " + start + " count: " + count);
809
               
810
                ObjectList ol = MNodeService.getInstance().listObjects(session, startTime, endTime, 
811
                        objectFormat, replicaStatus, start, count);
812
                
813
                StringReader sr = new StringReader(ol.toString());                
814
                out = response.getOutputStream();  
815
                response.setStatus(200);
816
                response.setContentType("text/xml");
817
                // Serialize and write it to the output stream
818
                
819
                try {
820
                    serializeServiceType(ObjectList.class, ol, out);
821
                } catch (JiBXException e) {
822
                    throw new ServiceFailure("1190", "Failed to serialize ObjectList: " + e.getMessage());
823
                }
824
            }
825
        } catch (BaseException e) {
826
                response.setStatus(500);
827
                serializeException(e, out);
828
        } catch (IOException e) {
829
            e.printStackTrace();
830
            response.setStatus(500);
831
            ServiceFailure sf = new ServiceFailure("1030", 
832
                    "IO Error in getObject: " + e.getMessage());
833
            serializeException(sf, out); 
834
        } catch(NumberFormatException ne) {
835
            response.setStatus(500);
836
            InvalidRequest ir = new InvalidRequest("1030", "Invalid format for parameter: " + ne.getMessage());
837
            serializeException(ir, out);
838
        } catch (Exception e) {
839
            e.printStackTrace();
840
            response.setStatus(500);
841
            ServiceFailure sf = new ServiceFailure("1030", 
842
                    "Exception " + e.getClass().getName() + " raised while handling listObjects request: " + 
843
                    e.getMessage());
844
            serializeException(sf, out);
845
        }
846
    }
847
    
848
    /**
849
     * Implements REST version of DataONE CRUD API --> getSystemMetadata
850
     * @param guid ID of data object to be read
851
     */
852
    protected void getSystemMetadataObject(String guid) {
853
        OutputStream out = null;
854
        try {
855
            response.setContentType("text/xml");
856
            response.setStatus(200);
857
            out = response.getOutputStream();
858
            Identifier id = new Identifier();
859
            id.setValue(guid);
860
            SystemMetadata sysmeta = MNodeService.getInstance().getSystemMetadata(session, id);
861
            
862
            // Serialize and write it to the output stream
863
            try {
864
                serializeServiceType(SystemMetadata.class, sysmeta, out);
865
            } catch (JiBXException e) {
866
                throw new ServiceFailure("1190", "Failed to serialize SystemMetadata: " + e.getMessage());
867
            }
868
        } catch (BaseException e) {
869
            response.setStatus(500);
870
                serializeException(e, out);
871
        } catch (IOException e) {
872
            response.setStatus(500);
873
            ServiceFailure sf = new ServiceFailure("1030", 
874
                    "IO Error in getSystemMetadataObject: " + e.getMessage());
875
            serializeException(sf, out);
876
        } finally {
877
            IOUtils.closeQuietly(out);
878
        }
879
    }
880
    
881
    
882
    /**
883
     * Inserts or updates the object
884
     * 
885
     * @param guid - ID of data object to be inserted or updated.  If action is update, the pid
886
     *               is the existing pid.  If insert, the pid is the new one
887
     * @throws InvalidRequest 
888
     * @throws ServiceFailure 
889
     * @throws FileNotFoundException 
890
     * @throws JiBXException 
891
     * @throws NotImplemented 
892
     * @throws InvalidSystemMetadata 
893
     * @throws InsufficientResources 
894
     * @throws UnsupportedType 
895
     * @throws IdentifierNotUnique 
896
     * @throws NotAuthorized 
897
     * @throws InvalidToken 
898
     * @throws NotFound 
899
     */
900
    protected void putObject(String pid, String action) throws ServiceFailure, InvalidRequest, FileNotFoundException, JiBXException, InvalidToken, NotAuthorized, IdentifierNotUnique, UnsupportedType, InsufficientResources, InvalidSystemMetadata, NotImplemented, NotFound {
901
        System.out.println("putObject with pid " + pid);
902
        logMetacat.debug("Entering putObject: " + pid + "/" + action);
903
        OutputStream out = null;
904
        try {
905
            out = response.getOutputStream();
906
            response.setStatus(200);
907
            response.setContentType("text/xml");
908
        } catch (IOException e1) {
909
            logMetacat.error("Could not get the output stream for writing in putObject");
910
        }
911
        
912
        // Read the incoming data from its Mime Multipart encoding
913
    	Map<String, File> files = collectMultipartFiles();
914
        InputStream object = null;
915
        InputStream sysmeta = null;
916

    
917
        File smFile = files.get("sysmeta");
918
        sysmeta = new FileInputStream(smFile);
919
        File objFile = files.get("object");
920
        object = new FileInputStream(objFile);
921
        
922
        if (action.equals(FUNCTION_NAME_INSERT)) { 
923
            // handle inserts
924
            logMetacat.debug("Commence creation...");
925
            SystemMetadata smd = (SystemMetadata) deserializeServiceType(SystemMetadata.class, sysmeta);
926

    
927
            Identifier id = new Identifier();
928
            id.setValue(pid);
929
            System.out.println("creating object with pid " + pid);
930
            Identifier rId = MNodeService.getInstance().create(session, id, object, smd);
931
            serializeServiceType(Identifier.class, rId, out);
932
            
933
        } else if (action.equals(FUNCTION_NAME_UPDATE)) {
934
        	// handle updates
935
        	
936
            // construct pids
937
            Identifier newPid = new Identifier();
938
            try {
939
            	String newPidString = multipartparams.get("newPid").get(0);
940
                newPid.setValue(newPidString);
941
            } catch (Exception e) {
942
				logMetacat.warn("newPid not given");
943
			}
944
            
945
            Identifier obsoletedPid = new Identifier();
946
            obsoletedPid.setValue(pid);
947
           
948
            logMetacat.debug("Commence update...");
949
            
950
            // get the systemmetadata object
951
            SystemMetadata smd = (SystemMetadata) deserializeServiceType(SystemMetadata.class, sysmeta);
952

    
953
            Identifier rId = MNodeService.getInstance().update(session, newPid, object, obsoletedPid, smd);
954
            serializeServiceType(Identifier.class, rId, out);
955
        } else {
956
            throw new InvalidRequest("1000", "Operation must be create or update.");
957
        }
958
            
959
            
960
    }
961

    
962
    /**
963
     * Handle delete 
964
     * @param guid ID of data object to be deleted
965
     * @throws IOException
966
     */
967
    private void deleteObject(String guid) throws IOException 
968
    {
969

    
970
        OutputStream out = response.getOutputStream();
971
        response.setStatus(200);
972
        response.setContentType("text/xml");
973

    
974
        Identifier id = new Identifier();
975
        id.setValue(guid);
976
        try {
977
            System.out.println("Calling delete");
978
            MNodeService.getInstance().delete(session, id);
979
            serializeServiceType(Identifier.class, id, out);
980
        } 
981
        catch (NotAuthorized e) {
982
            response.setStatus(500);
983
            serializeException(e, out);
984
        } catch (InvalidToken e) {
985
            response.setStatus(500);
986
            serializeException(e, out);
987
        } catch (ServiceFailure e) {
988
            response.setStatus(500);
989
            serializeException(e, out);
990
        } catch (NotImplemented e) {
991
            response.setStatus(500);
992
            serializeException(e, out);
993
        } catch (InvalidRequest e) {
994
            response.setStatus(500);
995
            serializeException(e, out);
996
        } catch(NotFound e) {
997
            response.setStatus(500);
998
            serializeException(e, out);
999
        } catch(JiBXException e) {
1000
            response.setStatus(500);
1001
            serializeException(new ServiceFailure("1350", "JiBXException: " + e.getMessage()), out);
1002
        }
1003
        out.close();
1004
    }
1005
    
1006
    
1007
    
1008
    
1009
    /**
1010
     * set the access perms on a document
1011
     * @throws Exception
1012
     */
1013
    protected void setaccess() throws Exception
1014
    {
1015
        try
1016
        {
1017
            String guid = params.get("guid")[0];
1018
            Identifier id = new Identifier();
1019
            id.setValue(guid);
1020
            String accesspolicy = params.get("accesspolicy")[0];
1021
            AccessPolicy accessPolicy = (AccessPolicy) deserializeServiceType(AccessPolicy.class, new ByteArrayInputStream(accesspolicy.getBytes("UTF-8")));
1022
            MNodeService.getInstance().setAccessPolicy(session, id, accessPolicy);
1023
        }
1024
        catch(Exception e)
1025
        {
1026
            response.setStatus(500);
1027
            printError("Error setting access: " + e.getClass() + ": " + e.getMessage(), response);
1028
            throw e;
1029
        }
1030
    }
1031

    
1032
}
(8-8/11)