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:05:43 -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.IOException;
29
import java.io.InputStream;
30
import java.io.OutputStream;
31
import java.io.PrintWriter;
32
import java.util.Date;
33
import java.util.Hashtable;
34
import java.util.Iterator;
35
import java.util.List;
36
import java.util.Map;
37
import java.util.Timer;
38

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

    
43
import org.apache.commons.io.IOUtils;
44
import org.apache.log4j.Logger;
45
import org.dataone.client.ObjectFormatCache;
46
import org.dataone.client.auth.CertificateManager;
47
import org.dataone.mimemultipart.MultipartRequest;
48
import org.dataone.mimemultipart.MultipartRequestResolver;
49
import org.dataone.service.exceptions.BaseException;
50
import org.dataone.service.exceptions.IdentifierNotUnique;
51
import org.dataone.service.exceptions.InsufficientResources;
52
import org.dataone.service.exceptions.InvalidRequest;
53
import org.dataone.service.exceptions.InvalidSystemMetadata;
54
import org.dataone.service.exceptions.InvalidToken;
55
import org.dataone.service.exceptions.NotAuthorized;
56
import org.dataone.service.exceptions.NotFound;
57
import org.dataone.service.exceptions.NotImplemented;
58
import org.dataone.service.exceptions.ServiceFailure;
59
import org.dataone.service.exceptions.UnsupportedType;
60
import org.dataone.service.types.AccessPolicy;
61
import org.dataone.service.types.Checksum;
62
import org.dataone.service.types.Event;
63
import org.dataone.service.types.Identifier;
64
import org.dataone.service.types.Log;
65
import org.dataone.service.types.ObjectFormat;
66
import org.dataone.service.types.ObjectFormatIdentifier;
67
import org.dataone.service.types.ObjectFormatList;
68
import org.dataone.service.types.ObjectLocationList;
69
import org.dataone.service.types.Permission;
70
import org.dataone.service.types.Subject;
71
import org.dataone.service.types.SystemMetadata;
72
import org.jibx.runtime.BindingDirectory;
73
import org.jibx.runtime.IBindingFactory;
74
import org.jibx.runtime.IUnmarshallingContext;
75
import org.jibx.runtime.JiBXException;
76

    
77
import edu.ucsb.nceas.metacat.IdentifierManager;
78
import edu.ucsb.nceas.metacat.MetacatHandler;
79
import edu.ucsb.nceas.metacat.dataone.CNodeService;
80

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

    
121
	/** CN-specific operations **/
122
    protected static final String RESOURCE_RESERVE = "reserve";
123
    protected static final String RESOURCE_FORMATS = "formats"; //remove from super
124
    protected static final String RESOURCE_RESOLVE = "resolve";
125
    protected static final String RESOURCE_ASSERT_RELATION = "assertRelation";
126
    protected static final String RESOURCE_OWNER = "owner";
127
    protected static final String RESOURCE_NOTIFY = "notify";
128
    protected static final String RESOURCE_META_REPLICATION = "meta/replication";
129
    protected static final String RESOURCE_META_POLICY = "meta/policy";
130
	
131
    public CNResourceHandler(ServletContext servletContext,
132
			HttpServletRequest request, HttpServletResponse response) {
133
		super(servletContext, request, response);
134
        logMetacat = Logger.getLogger(CNResourceHandler.class);
135
	}
136

    
137
	/**
138
     * This function is called from REST APU servlet and handles each request to the servlet 
139
     * 
140
     * @param httpVerb (GET, POST, PUT or DELETE)
141
     */
142
    public void handle(byte httpVerb) {
143
        try {
144
            //substring off the "d1/cn/" part of the url
145
        	String resourcePrefix = RESOURCE_BASE_URL + "/cn/";
146
            String resource = request.getServletPath();
147
            resource = resource.substring(resource.indexOf(resourcePrefix) + resourcePrefix.length());
148
            resource = resource.trim();
149
                        
150
            logMetacat.debug("handling verb " + httpVerb + " request with resource '" + resource + "'");
151
            boolean status = false;
152
            
153
            // load session from certificate in request
154
            // TODO: move to superclass
155
            session = CertificateManager.getInstance().getSession(request);
156
            
157
            if (resource != null) {
158

    
159
                params = new Hashtable<String, String[]>();
160
                initParams();
161

    
162
                Timer timer = new Timer();
163
                handler = new MetacatHandler(timer);
164

    
165
                if (resource.equals(RESOURCE_ACCESS_RULES) && httpVerb == PUT) {
166
                    logMetacat.debug("Setting access policy");
167
                    setaccess();
168
                    status = true;
169
                    logMetacat.debug("done setting access");
170
                    
171
                } else if (resource.equals(RESOURCE_META)) {
172
                    logMetacat.debug("Using resource: " + RESOURCE_META);
173
                    String objectId = request.getPathInfo();
174
                    if (objectId != null && objectId.length() > 1) {
175
                        objectId = request.getPathInfo().substring(1);
176
                    }
177
                    // get
178
                    if (httpVerb == GET) {
179
                        getSystemMetadataObject(objectId);
180
                        status = true;
181
                    }
182
                    // post to register system metadata
183
                    if (httpVerb == POST) {
184
                    	registerSystemMetadata(objectId);
185
                    	status = true;
186
                    }
187

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

    
248
                    String objectId = request.getPathInfo();
249
                    if (objectId != null && objectId.length() > 1) {
250
                        objectId = request.getPathInfo().substring(1);
251
                    }
252
                    else {
253
                        objectId = null;
254
                    }
255
                    
256
                    logMetacat.debug("objectId: " + objectId);
257
                    logMetacat.debug("verb:" + httpVerb);
258

    
259
                    if (httpVerb == GET) {
260
                        getObject(objectId);
261
                        status = true;
262
                    } else if (httpVerb == POST) {
263
                        putObject(objectId, FUNCTION_NAME_INSERT);
264
                        status = true;
265
                    } else if (httpVerb == PUT) {
266
                    	// TODO: this is not applicable for CN
267
                        putObject(objectId, FUNCTION_NAME_UPDATE);
268
                        status = true;
269
                    }
270
                    
271
                } else if (resource.equals(RESOURCE_FORMATS)) {
272
                  logMetacat.debug("Using resource: " + RESOURCE_FORMATS);
273
                  
274
                  // check for a format identifier
275
                  String fmtid = request.getPathInfo();
276
                  
277
                  if (fmtid != null && fmtid.length() > 1 ) {
278
                  	fmtid = request.getPathInfo().substring(1);
279
                  } else {
280
                  	fmtid = null;
281
                  }
282
                  
283
                  // handle each verb
284
                  if (httpVerb == GET) {
285
                  	if (fmtid == null) {
286
                  		// list the formats collection
287
                  		listFormats();
288
                  	} else {
289
                  		// get the specified format
290
                  		getFormat(fmtid);
291
                  	}
292
                  	status = true;
293
                  }
294
                  
295
                } else if (resource.equals(RESOURCE_LOG)) {
296
                    logMetacat.debug("Using resource: " + RESOURCE_LOG);
297
                    //handle log events
298
                    if (httpVerb == GET) {
299
                        getLog();
300
                        status = true;
301
                    }
302

    
303
                } else if (resource.equals(RESOURCE_CHECKSUM)) {
304
                    logMetacat.debug("Using resource: " + RESOURCE_CHECKSUM);
305
                    //handle checksum requests
306
                    if (httpVerb == GET) {
307
                    
308
                        String guid = request.getPathInfo();
309
                        if (guid != null && guid.length() > 1)
310
                            guid = request.getPathInfo().substring(1); //trim the slash
311
                        
312
                        Identifier guidid = new Identifier();
313
                        guidid.setValue(guid);
314
                        logMetacat.debug("getting checksum for object " + guid);
315
                        try {
316
                            Checksum c = CNodeService.getInstance().getChecksum(session, guidid);
317
                            logMetacat.debug("got checksum " + c.getValue());
318
                            response.setStatus(200);
319
                            logMetacat.debug("serializing response");
320
                            serializeServiceType(Checksum.class, c, response.getOutputStream());
321
                            logMetacat.debug("done serializing response.");
322
                        }
323
                        catch(NotAuthorized na)
324
                        {
325
                            na.setDetail_code("1400");
326
                            serializeException(na, response.getOutputStream());
327
                        }
328
                        catch(NotFound nf)
329
                        {
330
                            nf.setDetail_code("1420");
331
                            serializeException(nf, response.getOutputStream());
332
                        }
333
                        catch(InvalidRequest ir)
334
                        {
335
                            ir.setDetail_code("1402");
336
                            serializeException(ir, response.getOutputStream());
337
                        }
338
                        catch(ServiceFailure sf)
339
                        {
340
                            sf.setDetail_code("1410");
341
                            serializeException(sf, response.getOutputStream());
342
                        }
343
                        catch(InvalidToken it)
344
                        {
345
                            it.setDetail_code("1430");
346
                            serializeException(it, response.getOutputStream());
347
                        }
348
                        status = true;
349
                    }
350
                } 
351
                    
352
                if (!status) {
353
                    response.setStatus(400);
354
                    printError("Incorrect parameters!", response);
355
                }
356
            } else {
357
                response.setStatus(400);
358
                printError("Incorrect resource!", response);
359
            }
360
        } catch (BaseException be) {
361
        	// report Exceptions as clearly as possible
362
        	OutputStream out = null;
363
			try {
364
				out = response.getOutputStream();
365
			} catch (IOException e) {
366
				logMetacat.error("Could not get output stream from response", e);
367
			}
368
            serializeException(be, out);
369
        } catch (Exception e) {
370
            logMetacat.error(e.getClass() + ": " + e.getMessage(), e);
371
        }
372
    }
373
    
374
	/**
375
     * get the logs from the CrudService based on passed params.  Available 
376
     * params are token, fromDate, toDate, event.  See 
377
     * http://mule1.dataone.org/ArchitectureDocs/mn_api_crud.html#MN_crud.getLogRecords
378
     * for more info
379
     */
380
    private void getLog()
381
    {
382
        OutputStream out = null;
383
        try
384
        {
385
            out = response.getOutputStream();
386
            response.setStatus(200);
387
            response.setContentType("text/xml");
388
            String fromDateS = params.get("fromDate")[0];
389
            logMetacat.debug("param fromDateS: " + fromDateS);
390
            Date fromDate = null;
391
            String toDateS = params.get("toDate")[0];
392
            logMetacat.debug("param toDateS: " + toDateS);
393
            Date toDate = null;
394
            String eventS = params.get("event")[0];
395
            Event event = null;
396
            if(fromDateS != null)
397
            {
398
                //fromDate = dateFormat.parse(fromDateS);
399
                fromDate = parseDateAndConvertToGMT(fromDateS);
400
            }
401
            if(toDateS != null)
402
            {
403
                //toDate = dateFormat.parse(toDateS);
404
                toDate = parseDateAndConvertToGMT(toDateS);
405
            }
406
            if(eventS != null)
407
            {
408
                event = Event.convert(eventS);
409
            }
410
            logMetacat.debug("fromDate: " + fromDate + " toDate: " + toDate);
411
            
412
            Integer start = null;
413
            Integer count = null;
414
            try {
415
            	start =  Integer.parseInt(params.get("start")[0]);
416
            } catch (Exception e) {
417
				logMetacat.warn("Could not parse start: " + e.getMessage());
418
			}
419
            try {
420
            	count =  Integer.parseInt(params.get("count")[0]);
421
            } catch (Exception e) {
422
				logMetacat.warn("Could not count start: " + e.getMessage());
423
			}
424
            
425
            logMetacat.debug("calling crudservice.getLogRecords");
426
            Log log = CNodeService.getInstance().getLogRecords(session, fromDate, toDate, event, start, count);
427
            serializeServiceType(Log.class, log, out);
428
        }
429
        catch(Exception e)
430
        {
431
            String msg = "Could not get logs from CrudService: " + e.getClass() + ": " + e.getMessage();
432
            response.setStatus(500);
433
            ServiceFailure sf = new ServiceFailure("1490", msg);
434
            logMetacat.error(msg);
435
            e.printStackTrace();
436
            serializeException(sf, out);
437
        }
438
    }
439

    
440
    /**
441
     * Implements REST version of DataONE CRUD API --> get
442
     * @param guid ID of data object to be read
443
     */
444
    protected void getObject(String guid) {
445
        OutputStream out = null;
446
        try {
447
            out = response.getOutputStream();
448
            response.setStatus(200);
449
            
450
            if(guid != null)
451
            { //get a specific document                
452
                Identifier id = new Identifier();
453
                id.setValue(guid);
454
                try
455
                {
456
                    
457
                    SystemMetadata sm = CNodeService.getInstance().getSystemMetadata(session, id);
458
                    
459
                    //set the content type
460
                    if(sm.getObjectFormat().getFmtid().getValue().trim().equals(
461
                    		ObjectFormatCache.getInstance().getFormat("text/csv").getFmtid().getValue()))
462
                    {
463
                        response.setContentType("text/csv");
464
                        response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".csv");
465
                    }
466
                    else if(sm.getObjectFormat().getFmtid().getValue().trim().equals(
467
                    		ObjectFormatCache.getInstance().getFormat("text/plain").getFmtid().getValue()))
468
                    {
469
                        response.setContentType("text/plain");
470
                        response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".txt");
471
                    } 
472
                    else if(sm.getObjectFormat().getFmtid().getValue().trim().equals(
473
                    		ObjectFormatCache.getInstance().getFormat("application/octet-stream").getFmtid().getValue()))
474
                    {
475
                        response.setContentType("application/octet-stream");
476
                    }
477
                    else
478
                    {
479
                        response.setContentType("text/xml");
480
                        response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".xml");
481
                    }
482
                    
483
                    InputStream data = CNodeService.getInstance().get(session, id);
484
                    IOUtils.copyLarge(data, response.getOutputStream());
485
                }
486
                catch(InvalidToken it)
487
                {
488
                    response.setStatus(500);
489
                    serializeException(it, out); 
490
                }
491
                catch(ServiceFailure sf)
492
                {
493
                    response.setStatus(500);
494
                    serializeException(sf, out); 
495
                }
496
                catch(NotAuthorized na)
497
                {
498
                    response.setStatus(500);
499
                    serializeException(na, out); 
500
                }
501
                catch(NotFound nf)
502
                {
503
                    response.setStatus(500);
504
                    serializeException(nf, out); 
505
                }
506
                catch(NotImplemented ni)
507
                {
508
                    response.setStatus(500);
509
                    serializeException(ni, out); 
510
                }
511
                catch(Exception e)
512
                {
513
                    response.setStatus(500);
514
                    logMetacat.error("Error with Crud.get().  " +
515
                            "If this is an 'Exception producing data' error, " +
516
                            "go to CrudService.get() for better debugging.  " +
517
                            "Here's the error: " + e.getClass() + ": " + e.getMessage());
518
                    e.printStackTrace();
519
                    ServiceFailure sf = new ServiceFailure("1030", 
520
                            "IO Error in D1ResourceHandler.getObject: " + e.getClass() + ": " + e.getMessage());
521
                    serializeException(sf, out); 
522
                }
523
            }
524
            
525
        } catch (IOException e) {
526
            e.printStackTrace();
527
            response.setStatus(500);
528
            ServiceFailure sf = new ServiceFailure("1030", 
529
                    "IO Error in D1ResourceHandler.getObject: " + e.getMessage());
530
            serializeException(sf, out); 
531
        } catch(NumberFormatException ne) {
532
            response.setStatus(500);
533
            InvalidRequest ir = new InvalidRequest("1030", "Invalid format for parameter: " + ne.getMessage());
534
            serializeException(ir, out);
535
        } catch (Exception e) {
536
            e.printStackTrace();
537
            response.setStatus(500);
538
            ServiceFailure sf = new ServiceFailure("1030", 
539
                    "Exception " + e.getClass().getName() + " raised while handling listObjects request: " + 
540
                    e.getMessage());
541
            serializeException(sf, out);
542
        }
543
    }
544
    
545

    
546
    /**
547
     * Implements REST version of DataONE CRUD API --> getSystemMetadata
548
     * @param guid ID of data object to be read
549
     */
550
    protected void getSystemMetadataObject(String guid) {
551
        OutputStream out = null;
552
        try {
553
            response.setContentType("text/xml");
554
            response.setStatus(200);
555
            out = response.getOutputStream();
556
            Identifier id = new Identifier();
557
            id.setValue(guid);
558
            SystemMetadata sysmeta = CNodeService.getInstance().getSystemMetadata(session, id);
559
            
560
            // Serialize and write it to the output stream
561
            try {
562
                //TODO: look at the efficiency of this method.  The system metadata
563
                //is read from metacat (in CrudService) as xml, then serialized
564
                //to a SystemMetadat object, then returned here, then serizlized
565
                //back to XML to be sent to the response.
566
                serializeServiceType(SystemMetadata.class, sysmeta, out);
567
            } catch (JiBXException e) {
568
                throw new ServiceFailure("1190", "Failed to serialize SystemMetadata: " + e.getMessage());
569
            }
570
        } catch (BaseException e) {
571
            response.setStatus(500);
572
                serializeException(e, out);
573
        } catch (IOException e) {
574
            response.setStatus(500);
575
            ServiceFailure sf = new ServiceFailure("1030", 
576
                    "IO Error in D1ResourceHandler.getSystemMetadataObject: " + e.getMessage());
577
            serializeException(sf, out);
578
        } finally {
579
            IOUtils.closeQuietly(out);
580
        }
581
    }
582
    
583
    /**
584
     * Earthgrid API > Put Service >Put Function : calls MetacatHandler > handleInsertOrUpdateAction 
585
     * 
586
     * @param guid - ID of data object to be inserted or updated.  If action is update, the pid
587
     *               is the existing pid.  If insert, the pid is the new one
588
     * @throws IOException
589
     */
590
    protected void putObject(String pid, String action) {
591
        logMetacat.debug("putObject with pid " + pid);
592
        logMetacat.debug("Entering putObject: " + pid + "/" + action);
593
        OutputStream out = null;
594
        try {
595
            out = response.getOutputStream();
596
            response.setStatus(200);
597
            response.setContentType("text/xml");
598
        } catch (IOException e1) {
599
            logMetacat.error("Could not get the output stream for writing in putObject");
600
        }
601
        try {
602
            
603
            // Read the incoming data from its Mime Multipart encoding
604
            logMetacat.debug("Disassembling MIME multipart form");
605
            InputStream object = null;
606
            InputStream sysmeta = null;
607
            Map<String, List<String>> multipartparams;
608
            
609
            try
610
            {
611
                //String req = IOUtils.toString(request.getInputStream());
612
                //logMetacat.debug("request: " + req);
613
                //InputStream reqStr = IOUtils.toInputStream(req);
614
                InputStream reqStr = request.getInputStream();
615
                
616
                //handle MMP inputs
617
                File tmpDir = getTempDirectory();
618
                File tmpSMFile = new File(tmpDir + 
619
                        ".sysmeta." + new Date().getTime() + ".tmp");
620
                logMetacat.debug("temp dir: " + tmpDir.getAbsolutePath());
621
                MultipartRequestResolver mrr = new MultipartRequestResolver(
622
                        tmpDir.getAbsolutePath(), 1000000000, 0);
623
                MultipartRequest mr = mrr.resolveMultipart(request);
624
                logMetacat.debug("resolved multipart request");
625
                Map<String, File> files = mr.getMultipartFiles();
626
                if(files == null)
627
                {
628
                    throw new ServiceFailure("1202", "create/update must have multipart files with names 'object' and 'sysmeta'");
629
                }
630
                logMetacat.debug("got multipart files");
631
                
632
                if(files.keySet() == null)
633
                {
634
                    logMetacat.error("No file keys in MMP request.");
635
                    throw new ServiceFailure("1202", "No file keys found in MMP.  " +
636
                            "create/update must have multipart files with names 'object' and 'sysmeta'");
637
                }
638

    
639
		// for logging purposes, dump out the key-value pairs that constitute the request
640
		// 3 types exist: request params, multipart params, and multipart files
641
                Iterator it = files.keySet().iterator();
642
                logMetacat.debug("iterating through request parts: " + it);
643
                while(it.hasNext())
644
                {
645
                    String key = (String)it.next();
646
                    logMetacat.debug("files key: " + key);
647
                    logMetacat.debug("files value: " + files.get(key));
648
                }
649
                
650
                multipartparams = mr.getMultipartParameters();
651
                it = multipartparams.keySet().iterator();
652
                while(it.hasNext())
653
                {
654
                    String key = (String)it.next();
655
                    logMetacat.debug("multipartparams key: " + key);
656
                    logMetacat.debug("multipartparams value: " + multipartparams.get(key));
657
                }
658
                
659
                it = params.keySet().iterator();
660
                while(it.hasNext())
661
                {
662
                    String key = (String)it.next();
663
                    logMetacat.debug("param key: " + key);
664
                    logMetacat.debug("param value: " + params.get(key));
665
                }
666
		logMetacat.debug("done iterating the request...");
667

    
668
                File smFile = files.get("sysmeta");
669
		if (smFile == null) 
670
		    throw new InvalidRequest("1102", "Missing the required file-part 'sysmeta' from the multipart request.");
671
                logMetacat.debug("smFile: " + smFile.getAbsolutePath());
672
                sysmeta = new FileInputStream(smFile);
673
                File objFile = files.get("object");
674
		if (objFile == null) 
675
		    throw new InvalidRequest("1102", "Missing the required file-part 'object' from the multipart request.");
676

    
677
                logMetacat.debug("objectfile: " + objFile.getAbsolutePath());
678
                object = new FileInputStream(objFile);
679
                
680
                /*String obj = IOUtils.toString(object);
681
                String sm = IOUtils.toString(sysmeta);
682
                logMetacat.debug("object: " + obj);
683
                logMetacat.debug("sm: " + sm);
684
                object = IOUtils.toInputStream(obj);
685
                sysmeta = IOUtils.toInputStream(sm);*/
686
                
687
            }
688
            catch(org.apache.commons.fileupload.FileUploadException fue)
689
            {
690
                throw new ServiceFailure("1202", "Could not upload MMP files: " + fue.getMessage());
691
            }
692
            catch(IOException ioe)
693
            {
694
                throw new ServiceFailure("1202", 
695
                        "IOException when processing Mime Multipart: " + ioe.getMessage());
696
            }
697
            catch(Exception e)
698
            {
699
                throw new ServiceFailure("1202", "Error handling MMP upload: " + e.getClass() + ": " + e.getMessage());
700
            }
701
            
702
            if ( action.equals(FUNCTION_NAME_INSERT)) { //handle inserts
703

    
704
                // Check if the objectId exists
705
                IdentifierManager im = IdentifierManager.getInstance();
706
                if (im.identifierExists(pid)) {
707
                    throw new IdentifierNotUnique("1000", "Identifier is already in use: " + pid);
708
                }
709

    
710
                logMetacat.debug("Commence creation...");
711
                IBindingFactory bfact =
712
                    BindingDirectory.getFactory(SystemMetadata.class);
713
                IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
714
                SystemMetadata smd = (SystemMetadata) uctx.unmarshalDocument(sysmeta, null);
715

    
716
                Identifier id = new Identifier();
717
                id.setValue(pid);
718
                logMetacat.debug("creating object with pid " + id.getValue());
719
                Identifier rId = CNodeService.getInstance().create(session, id, object, smd);
720
                serializeServiceType(Identifier.class, rId, out);
721
                
722
            } else {
723
                throw new InvalidRequest("1000", "Operation must be create or update.");
724
            }
725
            
726
            //clean up the MMP files
727
            //parts.get("systemmetadata").delete();
728
            //parts.get("object").delete();
729
        } catch (NotAuthorized e) {
730
            response.setStatus(500);
731
            serializeException(e, out);
732
        } catch (InvalidToken e) {
733
            response.setStatus(500);
734
            serializeException(e, out);
735
        } catch (ServiceFailure e) {
736
            response.setStatus(500);
737
            serializeException(e, out);
738
        } catch (IdentifierNotUnique e) {
739
            response.setStatus(500);
740
            serializeException(e, out);
741
        } catch (UnsupportedType e) {
742
            response.setStatus(500);
743
            serializeException(e, out);
744
        } catch (InsufficientResources e) {
745
            response.setStatus(500);
746
            serializeException(e, out);
747
        } catch (InvalidSystemMetadata e) {
748
            response.setStatus(500);
749
            serializeException(e, out);
750
        } catch (NotImplemented e) {
751
            response.setStatus(500);
752
            serializeException(e, out);
753
        } catch (InvalidRequest e) {
754
            response.setStatus(500);
755
            serializeException(e, out);
756
        } /*catch (MessagingException e) {
757
            ServiceFailure sf = new ServiceFailure("1000", e.getMessage());
758
            serializeException(sf, out);
759
        } catch (IOException e) {
760
            response.setStatus(500);
761
            ServiceFailure sf = new ServiceFailure("1000", e.getMessage());
762
            serializeException(sf, out);
763
        }*/ catch (JiBXException e) {
764
            response.setStatus(500);
765
            e.printStackTrace(System.out);
766
            InvalidSystemMetadata ism = new InvalidSystemMetadata("1080", e.getMessage());
767
            serializeException(ism, out);
768
        }
769
    }
770

    
771
    /**
772
     * List the object formats registered with the system
773
     */
774
		private void listFormats() {
775
      logMetacat.debug("Entering listFormats()");
776
      // get the response output stream
777
      OutputStream out = null;
778
      
779
      try {
780
	      out = response.getOutputStream();
781
	      response.setStatus(200);
782
	      response.setContentType("text/xml");
783
	      
784
      } catch (IOException ioe) {
785
      	logMetacat.error("Could not get the output stream for writing" +
786
      	  "in D1ResourceHandler.listFormats()");
787
      
788
      }
789

    
790
      // get the object format list
791
      try {
792
	      ObjectFormatList objectFormatList = CNodeService.getInstance().listFormats();
793
	      serializeServiceType(ObjectFormatList.class, objectFormatList, out);
794
      
795
      } catch (InvalidRequest e) {
796
      	response.setStatus(200);
797
      	serializeException(e, out);
798
      	
799
      } catch (ServiceFailure e) {
800
      	response.setStatus(501);
801
      	serializeException(e, out);
802
      
803
      } catch (NotFound e) {
804
      	response.setStatus(200);
805
      	serializeException(e, out);
806
      
807
      } catch (InsufficientResources e) {
808
      	response.setStatus(200);
809
      	serializeException(e, out);
810
      
811
      } catch (NotImplemented e) {
812
      	response.setStatus(200);
813
      	serializeException(e, out);
814
      
815
      } catch (JiBXException jibxe) {
816
      	response.setStatus(501);
817
      	ServiceFailure e = 
818
      		new ServiceFailure("4841", "Unexpected exception from the service - " + 
819
        	                   jibxe.getClass() + ": " + jibxe.getMessage());
820
      	serializeException(e, out);
821
      	
822
      }
823
      
824
    }
825

    
826
		/**
827
     * Return the requested object format
828
     * 
829
     * @param fmtidStr the requested format identifier as a string
830
     */
831
    private void getFormat(String fmtidStr) {
832
      logMetacat.debug("Entering listFormats()");
833
      
834
      // get the response output stream
835
      OutputStream out = null;
836
      try {
837
	      out = response.getOutputStream();
838
	      response.setStatus(200);
839
	      response.setContentType("text/xml");
840
	      
841
      } catch (IOException ioe) {
842
      	logMetacat.error("Could not get the output stream for writing" +
843
      	  "in D1ResourceHandler.listFormats()");
844
      
845
      }
846
      
847
      ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
848
      fmtid.setValue(fmtidStr);
849
      
850
      try {
851
      	// get the specified object format
852
	      ObjectFormat objectFormat = CNodeService.getInstance().getFormat(fmtid);
853
	      serializeServiceType(ObjectFormat.class, objectFormat, out);
854

    
855
      } catch (InvalidRequest e) {
856
      	response.setStatus(200);
857
      	serializeException(e, out);
858
      
859
      } catch (ServiceFailure e) {
860
      	response.setStatus(501);
861
      	serializeException(e, out);
862
      
863
      } catch (NotFound e) {
864
      	response.setStatus(200);
865
      	serializeException(e, out);
866
      
867
      } catch (InsufficientResources e) {
868
      	response.setStatus(200);
869
      	serializeException(e, out);
870
      
871
      } catch (NotImplemented e) {
872
      	response.setStatus(200);
873
      	serializeException(e, out);
874
      
875
      } catch (JiBXException jibxe) {
876
      	ServiceFailure e = 
877
      		new ServiceFailure("4841", "Unexpected exception from the service - " + 
878
        	                   jibxe.getClass() + ": " + jibxe.getMessage());
879
      	serializeException(e, out);
880

    
881
      }
882
	    
883
    }
884
    
885
    /**
886
     * Reserve the given Identifier
887
     * @throws InvalidToken
888
     * @throws ServiceFailure
889
     * @throws NotAuthorized
890
     * @throws IdentifierNotUnique
891
     * @throws NotImplemented
892
     * @throws InvalidRequest
893
     * @throws IOException 
894
     */
895
    private void reserve() throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique, NotImplemented, InvalidRequest, IOException {
896
    	String id = params.get("pid")[0];
897
    	String format = params.get("format")[0];
898
		String scope = params.get("scope")[0];
899
		Identifier pid = new Identifier();
900
		pid.setValue(id);
901
		Identifier retPid = CNodeService.getInstance().reserveIdentifier(session, pid, scope, format);
902
		OutputStream out = response.getOutputStream();
903
		response.setStatus(200);
904
		response.setContentType("text/xml");
905
		try {
906
			serializeServiceType(Identifier.class, retPid, out);
907
		} catch (JiBXException e) {
908
	      throw new ServiceFailure("4210", 
909
	      				"Unexpected exception from the service - " + 
910
	        	                   e.getClass() + ": " + e.getMessage());
911
		}
912
		
913
    }
914
    
915
    private void resolve(String id) throws InvalidRequest, InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, IOException {
916
		Identifier pid = new Identifier();
917
		pid.setValue(id);
918
		ObjectLocationList locationList = CNodeService.getInstance().resolve(session, pid);
919
	    OutputStream out = response.getOutputStream();
920
		response.setStatus(200);
921
		response.setContentType("text/xml");
922
		try {
923
			serializeServiceType(ObjectLocationList.class, locationList, out);
924
		} catch (JiBXException e) {
925
	      throw new ServiceFailure("4150", 
926
	      				"Unexpected exception from the service - " + 
927
	        	                   e.getClass() + ": " + e.getMessage());
928
		}
929
    }
930

    
931
    private boolean assertRelation(String id) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, InvalidRequest, NotImplemented {
932
		Identifier pidOfSubject = new Identifier();
933
		pidOfSubject.setValue(id);
934
		Identifier pidOfObject = new Identifier();
935
		String relationship;
936
		relationship = params.get("relationship")[0];
937
		String objPid = params.get("pidOfObject")[0];
938
		pidOfObject.setValue(objPid);
939
		boolean result = CNodeService.getInstance().assertRelation(session, pidOfSubject, relationship, pidOfObject);
940
		response.setStatus(200);
941
		response.setContentType("text/xml");
942
		return result;
943
    }
944
    
945
    private void owner(String id) throws JiBXException, InvalidToken, ServiceFailure, NotFound, NotAuthorized, NotImplemented, InvalidRequest, IOException {
946
		Identifier pid = new Identifier();
947
		pid.setValue(id);
948
		String subjectStr = params.get("subject")[0];
949
		Subject subject = (Subject) deserializeServiceType(Subject.class, new ByteArrayInputStream(subjectStr.getBytes("UTF-8")));
950
		Identifier retPid = CNodeService.getInstance().setOwner(session, pid, subject);
951
		OutputStream out = response.getOutputStream();
952
		response.setStatus(200);
953
		response.setContentType("text/xml");
954
		try {
955
			serializeServiceType(Identifier.class, retPid, out);
956
		} catch (JiBXException e) {
957
	      throw new ServiceFailure("4490", 
958
	      				"Unexpected exception from the service - " + 
959
	        	                   e.getClass() + ": " + e.getMessage());
960
		}
961
		
962
    }
963
    
964
    private boolean isAuthorized(String id) throws ServiceFailure, InvalidToken, NotFound, NotAuthorized, NotImplemented, InvalidRequest {
965
		Identifier pid = new Identifier();
966
		pid.setValue(id);
967
		String permission = params.get("permission")[0];
968
		boolean result = CNodeService.getInstance().isAuthorized(session, pid, Permission.valueOf(permission));
969
		response.setStatus(200);
970
		response.setContentType("text/xml");
971
		return result;
972
    }
973
    
974
    /**
975
     * Register System Metadata without data or metadata object
976
     * @param pid identifier for System Metadata entry
977
     */
978
    protected void registerSystemMetadata(String pid) {
979
		logMetacat.debug("Entering registerSystemMetadata: " + pid);
980
		OutputStream out = null;
981
		try {
982
			out = response.getOutputStream();
983
			response.setStatus(200);
984
			response.setContentType("text/xml");
985
		} catch (IOException e1) {
986
			logMetacat.error("Could not get the output stream for writing in putObject");
987
		}
988
		try {
989

    
990
			// Read the incoming data from its Mime Multipart encoding
991
			logMetacat.debug("Disassembling MIME multipart form");
992
			InputStream sysmeta = null;
993
			Map<String, List<String>> multipartparams;
994

    
995
			try {
996

    
997
				// handle MMP inputs
998
				File tmpDir = getTempDirectory();
999

    
1000
				logMetacat.debug("temp dir: " + tmpDir.getAbsolutePath());
1001
				MultipartRequestResolver mrr = new MultipartRequestResolver(
1002
						tmpDir.getAbsolutePath(), 1000000000, 0);
1003
				MultipartRequest mr = mrr.resolveMultipart(request);
1004
				logMetacat.debug("resolved multipart request");
1005
				Map<String, File> files = mr.getMultipartFiles();
1006
				if (files == null) {
1007
					throw new ServiceFailure("1202",
1008
							"register meta must have multipart file with name 'sysmeta'");
1009
				}
1010
				logMetacat.debug("got multipart files");
1011

    
1012
				if (files.keySet() == null) {
1013
					logMetacat.error("No file keys in MMP request.");
1014
					throw new ServiceFailure(
1015
							"1202",
1016
							"No file keys found in MMP.  "
1017
									+ "register meta must have multipart file with name 'sysmeta'");
1018
				}
1019

    
1020
				// for logging purposes, dump out the key-value pairs that
1021
				// constitute the request
1022
				// 3 types exist: request params, multipart params, and
1023
				// multipart files
1024
				Iterator it = files.keySet().iterator();
1025
				logMetacat.debug("iterating through request parts: " + it);
1026
				while (it.hasNext()) {
1027
					String key = (String) it.next();
1028
					logMetacat.debug("files key: " + key);
1029
					logMetacat.debug("files value: " + files.get(key));
1030
				}
1031

    
1032
				multipartparams = mr.getMultipartParameters();
1033
				it = multipartparams.keySet().iterator();
1034
				while (it.hasNext()) {
1035
					String key = (String) it.next();
1036
					logMetacat.debug("multipartparams key: " + key);
1037
					logMetacat.debug("multipartparams value: "
1038
							+ multipartparams.get(key));
1039
				}
1040

    
1041
				it = params.keySet().iterator();
1042
				while (it.hasNext()) {
1043
					String key = (String) it.next();
1044
					logMetacat.debug("param key: " + key);
1045
					logMetacat.debug("param value: " + params.get(key));
1046
				}
1047
				logMetacat.debug("done iterating the request...");
1048

    
1049
				File smFile = files.get("sysmeta");
1050
				if (smFile == null) {
1051
					throw new InvalidRequest("1102",
1052
							"Missing the required file-part 'sysmeta' from the multipart request.");
1053
				}
1054
				logMetacat.debug("smFile: " + smFile.getAbsolutePath());
1055
				sysmeta = new FileInputStream(smFile);
1056

    
1057
			} catch (org.apache.commons.fileupload.FileUploadException fue) {
1058
				throw new ServiceFailure("1202", "Could not upload MMP files: "
1059
						+ fue.getMessage());
1060
			} catch (IOException ioe) {
1061
				throw new ServiceFailure("1202",
1062
						"IOException when processing Mime Multipart: "
1063
								+ ioe.getMessage());
1064
			} catch (Exception e) {
1065
				throw new ServiceFailure("1202", "Error handling MMP upload: "
1066
						+ e.getClass() + ": " + e.getMessage());
1067
			}
1068

    
1069
			// Check if the objectId exists
1070
			IdentifierManager im = IdentifierManager.getInstance();
1071
			if (im.identifierExists(pid)) {
1072
				throw new IdentifierNotUnique("1000",
1073
						"Identifier is already in use: " + pid);
1074
			}
1075

    
1076
			logMetacat.debug("Commence creation...");
1077
			IBindingFactory bfact = BindingDirectory
1078
					.getFactory(SystemMetadata.class);
1079
			IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
1080
			SystemMetadata systemMetadata = (SystemMetadata) uctx
1081
					.unmarshalDocument(sysmeta, null);
1082

    
1083
			Identifier guid = new Identifier();
1084
			guid.setValue(pid);
1085
			logMetacat.debug("registering system metadata with pid "
1086
					+ guid.getValue());
1087
			boolean result = CNodeService.getInstance().registerSystemMetadata(
1088
					session, guid, systemMetadata);
1089
			serializeServiceType(Boolean.class, result, out);
1090

    
1091
		} catch (NotAuthorized e) {
1092
			response.setStatus(500);
1093
			serializeException(e, out);
1094
		} catch (ServiceFailure e) {
1095
			response.setStatus(500);
1096
			serializeException(e, out);
1097
		} catch (IdentifierNotUnique e) {
1098
			response.setStatus(500);
1099
			serializeException(e, out);
1100
		} catch (NotImplemented e) {
1101
			response.setStatus(500);
1102
			serializeException(e, out);
1103
		} catch (InvalidRequest e) {
1104
			response.setStatus(500);
1105
			serializeException(e, out);
1106
		} catch (JiBXException e) {
1107
			response.setStatus(500);
1108
			e.printStackTrace(System.out);
1109
			InvalidSystemMetadata ism = new InvalidSystemMetadata("1080", e
1110
					.getMessage());
1111
			serializeException(ism, out);
1112
		} catch (InvalidSystemMetadata e) {
1113
			serializeException(e, out);
1114
    }
1115
	}
1116
    
1117
    /**
1118
     * set the access perms on a document
1119
     * @throws Exception
1120
     */
1121
    protected void setaccess() throws Exception
1122
    {
1123
        try
1124
        {
1125
            String guid = params.get("guid")[0];
1126
            Identifier id = new Identifier();
1127
            id.setValue(guid);
1128
            String accesspolicy = params.get("accesspolicy")[0];
1129
            AccessPolicy accessPolicy = (AccessPolicy) deserializeServiceType(AccessPolicy.class, new ByteArrayInputStream(accesspolicy.getBytes("UTF-8")));
1130
            CNodeService.getInstance().setAccessPolicy(session, id, accessPolicy);
1131
        }
1132
        catch(Exception e)
1133
        {
1134
            response.setStatus(500);
1135
            printError("Error setting access in D1ResourceHandler: " + e.getClass() + ": " + e.getMessage(), response);
1136
            throw e;
1137
        }
1138
    }
1139
    
1140
    /**
1141
     * Earthgrid API > Query Service > Query Function : translates ecogrid query document to metacat query 
1142
     * then calls DBQuery > createResultDocument function and then again translate resultset to ecogrid resultset
1143
     * 
1144
     * NOTE:
1145
     *      This is the only method that uses EcoGrid classes for its implementation.  
1146
     *      It does so because it takes an EcoGrid Query as input, and outputs an
1147
     *      EcoGrid ResultSet document.  These documents are parsed by the auto-generated
1148
     *      EcoGrid classes from axis, and so we link to them here rather than re-inventing them.
1149
     *      This creates a circular dependency, because the Metacat classes are needed
1150
     *      to build the EcoGrid implementation, and the EcoGrid jars are needed to build this query()
1151
     *      method.  This circularity could be resolved by moving the EcoGrid classes
1152
     *      to Metacat directly.  As we transition away from EcoGrid SOAP methods in
1153
     *      favor of these REST interfaces, this circular dependency can be eliminated.
1154
     *        
1155
     * @throws Exception
1156
     */
1157
    private void query() throws Exception {
1158
        /*  This block commented out because of the EcoGrid circular dependency.
1159
         *  For now, query will not be supported until the circularity can be
1160
         *  resolved, probably by moving the ecogrid query syntax transformers
1161
         *  directly into the Metacat codebase.  MBJ 2010-02-03
1162
         
1163
        try {
1164
            EcogridQueryParser parser = new EcogridQueryParser(request
1165
                    .getReader());
1166
            parser.parseXML();
1167
            QueryType queryType = parser.getEcogridQuery();
1168
            EcogridJavaToMetacatJavaQueryTransformer queryTransformer = 
1169
                new EcogridJavaToMetacatJavaQueryTransformer();
1170
            QuerySpecification metacatQuery = queryTransformer
1171
                    .transform(queryType);
1172

    
1173
            DBQuery metacat = new DBQuery();
1174

    
1175
            boolean useXMLIndex = (new Boolean(PropertyService
1176
                    .getProperty("database.usexmlindex"))).booleanValue();
1177
            String xmlquery = "query"; // we don't care the query in resultset,
1178
            // the query can be anything
1179
            PrintWriter out = null; // we don't want metacat result, so set out null
1180

    
1181
            // parameter: queryspecification, user, group, usingIndexOrNot
1182
            StringBuffer result = metacat.createResultDocument(xmlquery,
1183
                    metacatQuery, out, username, groupNames, useXMLIndex);
1184

    
1185
            // create result set transfer       
1186
            String saxparser = PropertyService.getProperty("xml.saxparser");
1187
            MetacatResultsetParser metacatResultsetParser = new MetacatResultsetParser(
1188
                    new StringReader(result.toString()), saxparser, queryType
1189
                            .getNamespace().get_value());
1190
            ResultsetType records = metacatResultsetParser.getEcogridResult();
1191

    
1192
            System.out
1193
                    .println(EcogridResultsetTransformer.toXMLString(records));
1194
            response.setContentType("text/xml");
1195
            out = response.getWriter();
1196
            out.print(EcogridResultsetTransformer.toXMLString(records));
1197

    
1198
        } catch (Exception e) {
1199
            e.printStackTrace();
1200
        }*/
1201
        response.setContentType("text/xml");
1202
        response.setStatus(501);
1203
        PrintWriter out = response.getWriter();
1204
        out.print("<error>Query operation not yet supported by Metacat.</error>");
1205
        out.close();
1206
    }
1207

    
1208
}
(1-1/11)