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: Serhan AKIN $'
7
 *     '$Date: 2009-06-13 15:28:13 +0300  $'
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.FileOutputStream;
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.net.URL;
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.TimeZone;
45
import java.util.Timer;
46

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

    
51
import org.apache.commons.io.IOUtils;
52
import org.apache.log4j.Logger;
53
import org.apache.maven.artifact.ant.shaded.IOUtil;
54
import org.dataone.client.MNode;
55
import org.dataone.client.ObjectFormatCache;
56
import org.dataone.mimemultipart.MultipartRequest;
57
import org.dataone.mimemultipart.MultipartRequestResolver;
58
import org.dataone.service.NodeListParser;
59
import org.dataone.service.exceptions.BaseException;
60
import org.dataone.service.exceptions.IdentifierNotUnique;
61
import org.dataone.service.exceptions.InsufficientResources;
62
import org.dataone.service.exceptions.InvalidRequest;
63
import org.dataone.service.exceptions.InvalidSystemMetadata;
64
import org.dataone.service.exceptions.InvalidToken;
65
import org.dataone.service.exceptions.NotAuthorized;
66
import org.dataone.service.exceptions.NotFound;
67
import org.dataone.service.exceptions.NotImplemented;
68
import org.dataone.service.exceptions.ServiceFailure;
69
import org.dataone.service.exceptions.UnsupportedType;
70
import org.dataone.service.types.AuthToken;
71
import org.dataone.service.types.Checksum;
72
import org.dataone.service.types.DescribeResponse;
73
import org.dataone.service.types.Event;
74
import org.dataone.service.types.Identifier;
75
import org.dataone.service.types.Log;
76
import org.dataone.service.types.Node;
77
import org.dataone.service.types.NodeList;
78
import org.dataone.service.types.NodeReference;
79
import org.dataone.service.types.NodeType;
80
import org.dataone.service.types.ObjectFormat;
81
import org.dataone.service.types.ObjectList;
82
import org.dataone.service.types.Service;
83
import org.dataone.service.types.ServiceMethod;
84
import org.dataone.service.types.Services;
85
import org.dataone.service.types.Session;
86
import org.dataone.service.types.SystemMetadata;
87
import org.dataone.service.types.util.ServiceTypeUtil;
88
import org.jibx.runtime.BindingDirectory;
89
import org.jibx.runtime.IBindingFactory;
90
import org.jibx.runtime.IUnmarshallingContext;
91
import org.jibx.runtime.JiBXException;
92

    
93
import edu.ucsb.nceas.metacat.DBUtil;
94
import edu.ucsb.nceas.metacat.IdentifierManager;
95
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
96
import edu.ucsb.nceas.metacat.MetaCatServlet;
97
import edu.ucsb.nceas.metacat.MetacatHandler;
98
import edu.ucsb.nceas.metacat.dataone.CNCoreImpl;
99
import edu.ucsb.nceas.metacat.dataone.CrudService;
100
import edu.ucsb.nceas.metacat.dataone.HealthService;
101
import edu.ucsb.nceas.metacat.properties.PropertyService;
102
import edu.ucsb.nceas.metacat.service.SessionService;
103
import edu.ucsb.nceas.metacat.util.RequestUtil;
104
import edu.ucsb.nceas.metacat.util.SessionData;
105
import edu.ucsb.nceas.metacat.util.SystemUtil;
106
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
107
/**
108
 * 
109
 * Implements Earthgrid REST API to Metacat <br/><br/> 
110
 * 
111
 * <ul>
112
 * <li>
113
 * <h3> EarthGrid Query Service</h3>
114
 * <ul><li>
115
 * <h3>Get & Authenticated Get:</h3> 
116
 * is equal to Metacat's read action and returns a data file having
117
 * the specified <doc-id> in the resource path. For authenticated Get service, a session id must be provided 
118
 * in the query string. <br/><br/>
119
 * 
120
 * <b>REST URL:</b> <code>GET, [context-root]/object/[doc-id]?sessionid=[sessionid] </code><br/>
121
 * <b>Returns:</b> data file <br/><br/>
122
 * </li>
123
 * 
124
 * <li>
125
 * <h3>Query & Authenticated Query:</h3> 
126
 * Metacat's equivalent is squery action but this function 
127
 * receives a Earthgrid query document and returns Earthgrid resultset document by transforming those documents
128
 * to Metacat's equivalents by the means of Metacat Implementation in Earthgrid library. For authenticated Query service 
129
 * a session id must be provided in the query string. See Earthgrid (a.k.a. Ecogrid) project for XSD files of 
130
 * query and resultset documents<br/><br/>
131
 * 
132
 * <b>REST URL:</b> <code>POST, [context-root]/object?sessionid=[sessionid]</code>    <br/>
133
 * <b>POST Data:</b> Earthgrid query document , Content-type: <code>text/xml</code><br/>
134
 * <b>Returns:</b> Earthgrid resultset document<br/><br/>
135
 * 
136
 * </li>
137
 * </ul>
138
 * 
139
 * </li>
140
 * 
141
 * <li>
142
 * <h3> EarthGrid Authentication Service</h3>
143
 * <ul><li>
144
 * <h3>Login: </h3> 
145
 * Receives username and password parameters in POST data and 
146
 * returns SessionId (in XML format) or failure message and uses MetacatHandler's handleLoginAction function<br/><br/>
147
 *  
148
 * <b>REST URL:</b> <code>POST, [context-root]/session?op=login</code> <br/>
149
 * <b>POST Data:</b> username=[username]&password=[password], Content-type: <code>application/x-www-form-urlencoded</code>
150
 * <b>Returns:</b> sessionId in XML format<br/><br/>
151
 * </li>
152
 * 
153
 * <li>
154
 * <h3>Logout: </h3> 
155
 * Receives session Id parameters in querystring and returns xml message, calls 
156
 * MetacatHandler's handleLogoutAction function<br/><br/>
157
 *  
158
 * <b>REST URL:</b> <code>GET, [context-root]/session?op=logout&sessionid=[sessionid]</code>   <br/>
159
 * <b>Returns:</b> message in XML format<br/><br/>
160
 * </li>
161
 * </ul>
162
 * 
163
 * <li>
164
 * <h3>EarthGrid Put Service</h3>
165
 * 
166
 * <ul>
167
 * <li><h3>Update/Insert: </h3>     
168
 * <br/>
169
 * <b>REST URL:</b> <code>PUT, [context-root]/object/[doc-id]?op={update|insert}&sessionid=[sessionid]</code>   <br/>
170
 * <b>POST Data:</b> document object, Content-type: <code>text/xml</code><br/>
171
 * <b>Returns:</b> message in XML format<br/><br/>
172
 * </li>
173
 * 
174
 * <li><h3>Delete: </h3>        
175
 * <br/>
176
 * <b>REST URL:</b> <code>DELETE, [context-root]/object/[doc-id]?sessionid=[sessionid]</code>   <br/>
177
 * <b>Returns:</b> message in XML format<br/><br/>
178
 * </li>
179

    
180
 * </ul>
181
 * </li>
182
 * 
183
 * <li>
184
 * <h3>EarthGrid Identifier Service</h3><br/>
185
 * 
186
 * <ul>
187
 * <li><h3>isRegistered: </h3>      <br/>
188
 * <b>REST URL:</b> <code>GET, [context-root]/identifier/[doc-id]?op=isregistered</code>   <br/>
189
 * <b>Returns:</b> message in XML format<br/><br/>
190
 * </li>
191

    
192
 * <li><h3>getAllDocIds:</h3>       <br/>       
193
 * <b>REST URL:</b> <code>GET, [context-root]/identifier?op=getalldocids</code>   <br/>
194
 * <b>Returns:</b> document id list in XML format<br/><br/>
195
 * </li>
196
 * 
197
 * <li><h3>addLSID Function:</h3> 
198
 * Metacat does not support this function       <br/>
199
 * <b>REST URL:</b> <code>PUT, [context-root]/identifier/[doc-id]</code>   <br/>
200
 * <b>Returns:</b> error message in XML format<br/><br/>
201
 * </li>
202
 * 
203
 * <li><h3>getNextRevision:</h3>        <br/>
204
 * <b>REST URL:</b> <code>GET, [context-root]/identifier/[doc-id]?op=getnextrevision</code>   <br/>
205
 * <b>Returns:</b> message in XML format<br/><br/>
206
 * </li>
207
 * 
208
 * <li><h3>getNextObject:</h3>      <br/>
209
 * <b>REST URL:</b> <code>GET, [context-root]/identifier?op=getnextobject&scope=[scope]</code>   <br/>
210
 * <b>Returns:</b> message in XML format<br/><br/>
211
 * </li>
212
 * 
213
 * </li>
214
 * </ul>
215
 * 
216
 */
217
public class ResourceHandler {
218

    
219
    /**HTTP Verb GET*/
220
    public static final byte GET = 1;
221
    /**HTTP Verb POST*/
222
    public static final byte POST = 2;
223
    /**HTTP Verb PUT*/
224
    public static final byte PUT = 3;
225
    /**HTTP Verb DELETE*/
226
    public static final byte DELETE = 4;
227
    /**HTTP Verb HEAD*/
228
    public static final byte HEAD = 5;
229

    
230
    /*
231
     * API Resources
232
     */
233
    private static final String RESOURCE_OBJECTS = "object";
234
    private static final String RESOURCE_FORMATS = "formats";
235
    private static final String RESOURCE_META = "meta";
236
    private static final String RESOURCE_SESSION = "session";
237
    private static final String RESOURCE_IDENTIFIER = "identifier";
238
    private static final String RESOURCE_LOG = "log";
239
    private static final String RESOURCE_CHECKSUM = "checksum";
240
    private static final String RESOURCE_MONITOR = "monitor";
241
    private static final String RESOURCE_BASE_URL = "d1";
242
    private static final String RESOURCE_REPLICATE = "replicate";
243

    
244
    /*
245
     * API Functions used as URL parameters
246
     */
247
    private static final String FUNCTION_KEYWORD = "op";
248
    private static final String FUNCTION_NAME_LOGIN = "login";
249
    private static final String FUNCTION_NAME_LOGOUT = "logout";
250
    private static final String FUNCTION_NAME_SET_ACCESS = "setaccess";
251
    private static final String FUNCTION_NAME_ISREGISTERED = "isregistered";
252
    private static final String FUNCTION_NAME_GETALLDOCS = "getalldocids";
253
    private static final String FUNCTION_NAME_GETNEXTREV = "getnextrevision";
254
    private static final String FUNCTION_NAME_GETNEXTOBJ = "getnextobject";
255
    private static final String FUNCTION_NAME_INSERT = "insert";
256
    private static final String FUNCTION_NAME_UPDATE = "update";
257
    private static final String FUNCTION_NAME_GENERATE_MISSING_SYSTEM_METADATA = "generatemissingsystemmetadata";
258

    
259
    private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
260
    
261
    private ServletContext servletContext;
262
    private Logger logMetacat;
263
    private MetacatHandler handler;
264
    private HttpServletRequest request;
265
    private HttpServletResponse response;
266
    private String username;
267
    private String password;
268
    private String sessionId;
269
    private String[] groupNames;
270

    
271
    private Hashtable<String, String[]> params;
272

    
273
    /**Initializes new instance by setting servlet context,request and response*/
274
    public ResourceHandler(ServletContext servletContext,
275
            HttpServletRequest request, HttpServletResponse response) {
276
        this.servletContext = servletContext;
277
        this.request = request;
278
        this.response = response;
279
    }
280

    
281
    /**
282
     * This function is called from REST APU servlet and handles each request to the servlet 
283
     * 
284
     * @param httpVerb (GET, POST, PUT or DELETE)
285
     */
286
    public void handle(byte httpVerb) {
287
        logMetacat = Logger.getLogger(ResourceHandler.class);
288
        try {
289
            String resource = request.getServletPath();
290
            if(resource.endsWith("d1/") || resource.endsWith("d1"))
291
            {
292
                resource = RESOURCE_BASE_URL;
293
            }
294
            else
295
            {
296
                //substring off the /d1/
297
                resource = resource.substring(resource.indexOf("d1/") + 3, resource.length());
298
                resource = resource.trim();
299
            }
300
            
301
            String verb = "";
302
            
303
            System.out.println("handling verb " + httpVerb + " request with resource '" + resource + "'");
304
            System.out.println("resource: '" + resource + "'");
305
            System.out.println("resource_monitor: '" + RESOURCE_MONITOR + "'");
306
            boolean status = false;
307
            loadSessionData();
308

    
309
            if (resource != null) {
310
                //resource = request.getServletPath().substring(1);
311

    
312
                params = new Hashtable<String, String[]>();
313
                initParams();
314

    
315
                Timer timer = new Timer();
316
                handler = new MetacatHandler(timer);
317

    
318
                if(resource.equals(RESOURCE_BASE_URL)) {
319
                    //node registry response
320
                    System.out.println("Using resource 'd1' (node registry response)");
321
                    createNodeResponse();
322
                    status = true;
323
                    
324
                } else if (resource.equals(RESOURCE_SESSION) && 
325
                        httpVerb == POST && 
326
                        params.get(FUNCTION_KEYWORD) != null) {
327
                    System.out.println("Using resource 'session'");
328
                    //System.out.println("function_keyword: " + params.get(FUNCTION_KEYWORD)[0]);
329
                    if (params.get(FUNCTION_KEYWORD)[0].equals(FUNCTION_NAME_LOGIN)) {
330
                        login();
331
                        status = true;
332
                    } else if (params.get(FUNCTION_KEYWORD)[0].equals(FUNCTION_NAME_LOGOUT)) {
333
                        logout();
334
                        status = true;
335
                    } else if (params.get(FUNCTION_KEYWORD)[0].equals(FUNCTION_NAME_SET_ACCESS)) {
336
                        setaccess();
337
                        status = true;
338
                        System.out.println("done setting access");
339
                    }
340
                } else if (resource.equals(RESOURCE_META)) {
341
                    System.out.println("Using resource 'meta'");
342
                    if (params != null && params.get(FUNCTION_KEYWORD) != null &&
343
                            params.get(FUNCTION_KEYWORD)[0].equals(FUNCTION_NAME_GENERATE_MISSING_SYSTEM_METADATA))
344
                    { 
345
                        status = true;
346
                    }
347
                    else
348
                    {
349
                        String objectId = request.getPathInfo();
350
                        if (objectId != null && objectId.length() > 1) 
351
                        {
352
                            objectId = request.getPathInfo().substring(1);
353
                        }
354
                        
355
                        // get
356
                        if (httpVerb == GET) {
357
	                        getSystemMetadataObject(objectId);
358
	                        status = true;
359
                        }
360
                        
361
                        // post to register system metadata
362
                        if (httpVerb == POST) {
363
                        	registerSystemMetadata(objectId);
364
                        	status = true;
365
                        }
366
                        
367
                    }
368

    
369
                } else if (resource.equals(RESOURCE_OBJECTS)) {
370
                    System.out.println("Using resource 'object'");
371
                    logMetacat.debug("D1 Rest: Starting resource processing...");
372
                    loadSessionData();
373

    
374
                    String objectId = request.getPathInfo();
375
                    if (objectId != null && objectId.length() > 1) 
376
                    {
377
                        objectId = request.getPathInfo().substring(1);
378
                    }
379
                    else
380
                    {
381
                        objectId = null;
382
                    }
383
                    
384
                    System.out.println("objectId in ReasourceHandler.handle: " + objectId);
385

    
386
                    logMetacat.debug("verb:" + httpVerb);
387

    
388
                    if (httpVerb == GET) {
389
                        getObject(objectId);
390
                        status = true;
391
                    } else if (httpVerb == POST) {
392
                        putObject(objectId, FUNCTION_NAME_INSERT);
393
                        status = true;
394
                    } else if (httpVerb == PUT) {
395
                        putObject(objectId, FUNCTION_NAME_UPDATE);
396
                        status = true;
397
                    } else if (httpVerb == DELETE) {
398
                        deleteObject(objectId);
399
                        status = true;
400
                    } else if (httpVerb == HEAD) {
401
                        describeObject(objectId);
402
                        status = true;
403
                    }
404
                    
405
                } else if (resource.equals(RESOURCE_FORMATS)) {
406
                  System.out.println("Using resource 'formats'");
407

    
408
                } else if (resource.equals(RESOURCE_IDENTIFIER)) {
409
                    System.out.println("Using resource 'identifier'");
410
                    String identifierId = request.getPathInfo();
411
                    if (identifierId != null && identifierId.length() > 1)
412
                        identifierId = request.getPathInfo().substring(1); //trim the slash
413

    
414
                    if (httpVerb == GET) {
415
                        String op = params.get(FUNCTION_KEYWORD)[0];
416
                        if (op.equals(FUNCTION_NAME_ISREGISTERED)) {
417
                            isRegistered(identifierId);
418
                            status = true;
419
                        } else if (op.equals(FUNCTION_NAME_GETALLDOCS)) {
420
                            getAllDocIds();
421
                            status = true;
422
                        } else if (op.equals(FUNCTION_NAME_GETNEXTREV)) {
423
                            getNextRevision(identifierId);
424
                            status = true;
425
                        } else if (op.equals(FUNCTION_NAME_GETNEXTOBJ)) {
426
                            getNextObject();
427
                            status = true;
428
                        } 
429

    
430
                    } else if (httpVerb == PUT) {
431
                        //Earthgrid API > Identifier Service > addLSID Function 
432
                        response.setStatus(501);
433
                        printError(
434
                                "This method is not supported by metacat.  To "
435
                                + "add a new LSID, add a document to metacat.",
436
                                response);
437
                        status = true;
438
                    }
439

    
440
                } else if (resource.equals(RESOURCE_LOG)) {
441
                    System.out.println("Using resource 'log'");
442
                    //handle log events
443
                    if(httpVerb == GET)
444
                    {
445
                        getLog();
446
                        status = true;
447
                    }
448
                    else
449
                    {
450
                        //change to D1 spec for specifying which http methods are allowed for a resource
451
                        response.setStatus(501);
452
                        printError("POST, PUT, DELETE is not supported for logs.", response);
453
                        status = true;
454
                    }
455

    
456
                } else if(resource.equals(RESOURCE_CHECKSUM)) {
457
                    System.out.println("Using resource 'checksum'");
458
                    //handle checksum requests
459
                    if(httpVerb == GET)
460
                    {
461
                        String checksumAlgorithm = "MD5";
462
                    
463
                        String guid = request.getPathInfo();
464
                        if (guid != null && guid.length() > 1)
465
                            guid = request.getPathInfo().substring(1); //trim the slash
466
                        
467
                        Identifier guidid = new Identifier();
468
                        guidid.setValue(guid);
469
                        AuthToken token = new AuthToken(sessionId);
470
                        try
471
                        {
472
                            checksumAlgorithm = params.get("checksumAlgorithm")[0];
473
                        }
474
                        catch(Exception e)
475
                        {
476
                            //do nothing.  default to MD5
477
                        }
478
                        System.out.println("getting checksum for object " + guid +
479
                                " with algorithm " + checksumAlgorithm);
480
                        try
481
                        {
482
                            Checksum c = CrudService.getInstance().getChecksum(token, guidid, checksumAlgorithm);
483
                            System.out.println("got checksum " + c.getValue());
484
                            response.setStatus(200);
485
                            System.out.println("serializing response");
486
                            serializeServiceType(Checksum.class, c, response.getOutputStream());
487
                            System.out.println("done serializing response.");
488
                        }
489
                        catch(NotAuthorized na)
490
                        {
491
                            na.setDetail_code("1400");
492
                            serializeException(na, response.getOutputStream());
493
                        }
494
                        catch(NotFound nf)
495
                        {
496
                            nf.setDetail_code("1420");
497
                            serializeException(nf, response.getOutputStream());
498
                        }
499
                        catch(InvalidRequest ir)
500
                        {
501
                            ir.setDetail_code("1402");
502
                            serializeException(ir, response.getOutputStream());
503
                        }
504
                        catch(ServiceFailure sf)
505
                        {
506
                            sf.setDetail_code("1410");
507
                            serializeException(sf, response.getOutputStream());
508
                        }
509
                        catch(InvalidToken it)
510
                        {
511
                            it.setDetail_code("1430");
512
                            serializeException(it, response.getOutputStream());
513
                        }
514
                        status = true;
515
                    }
516
                } else if(resource.equals(RESOURCE_MONITOR)) {
517
                    //health monitoring calls
518
                    System.out.println("processing monitor request");
519
                    String pathInfo = request.getPathInfo();
520
                    if(httpVerb == GET)
521
                    {
522
                        System.out.println("verb is GET");
523
                        System.out.println("pathInfo is " + pathInfo);
524
                        pathInfo = pathInfo.substring(1);
525
                        HealthService hs = new HealthService(request, response);
526
                        if (pathInfo.toLowerCase().equals("ping")) {
527
                            System.out.println("processing ping request");
528
                            hs.ping();
529
                        } else if (pathInfo.toLowerCase().equals("status")) {
530
                            System.out.println("processing status request");
531
                            hs.getStatus();
532
                        } else if (pathInfo.toLowerCase().equals("object")) {
533
                            System.out.println("processing object request");
534
                            boolean day = false;
535
                            Identifier pid = null;
536
                            String url = null;
537
                            ObjectFormat of = null;
538
                            Date time = null;
539
                            
540
                            if(params.containsKey("day"))
541
                            {
542
                               day = true; 
543
                            }
544
                            if(params.containsKey("pid"))
545
                            {
546
                                String id = params.get("pid")[0];
547
                                pid = new Identifier();
548
                                pid.setValue(id);
549
                            }
550
                            if(params.containsKey("url"))
551
                            {
552
                                url = params.get("url")[0];
553
                            }
554
                            if(params.containsKey("format"))
555
                            {
556
                                String format = params.get("format")[0];
557
                                of = ObjectFormatCache.getFormat(format);
558
                            }
559
                            if(params.containsKey("time"))
560
                            {
561
                                String t = params.get("time")[0];
562
                                time = dateFormat.parse(t);
563
                            }
564
                            
565
                            hs.getObjectStatistics(day, pid, url, of, time);
566
                        } else if (pathInfo.toLowerCase().equals("event")) {
567
                            System.out.println("processing event request");
568
                            boolean day = false;
569
                            Identifier pid = null;
570
                            Date created = null;
571
                            ObjectFormat of = null;
572
                            Date time = null;
573
                            String ipAddress = null;
574
                            String event = null;
575
                            
576
                            if(params.containsKey("day"))
577
                            {
578
                               day = true; 
579
                            }
580
                            if(params.containsKey("pid"))
581
                            {
582
                                String id = params.get("pid")[0];
583
                                pid = new Identifier();
584
                                pid.setValue(id);
585
                            }
586
                            if(params.containsKey("created"))
587
                            {
588
                                String t = params.get("created")[0];
589
                                created = dateFormat.parse(t);
590
                            }
591
                            if(params.containsKey("format"))
592
                            {
593
                                String format = params.get("format")[0];
594
                                of = ObjectFormatCache.getFormat(format);
595
                            }
596
                            if(params.containsKey("eventtime"))
597
                            {
598
                                String t = params.get("eventtime")[0];
599
                                time = dateFormat.parse(t);
600
                            }
601
                            if(params.containsKey("ip_address"))
602
                            {
603
                                ipAddress = params.get("ip_address")[0];
604
                            }
605
                            if(params.containsKey("event"))
606
                            {
607
                                event = params.get("event")[0];
608
                            }
609
                            
610
                            hs.getOperationStatistics(day, pid, of, created, time, ipAddress, event);
611
                        }
612
                    }
613
                    status = true;
614
                } else if(resource.equals(RESOURCE_REPLICATE)) {
615
                    System.out.println("processing replicate request");
616
                    replicate(httpVerb, request, response);
617
                    status = true;
618
                }
619
                    
620
                if (!status)
621
                {
622
                    response.setStatus(400);
623
                    printError("Incorrect parameters!", response);
624
                }
625
            } else {
626
                response.setStatus(400);
627
                printError("Incorrect resource!", response);
628
            }
629
        } catch (Exception e) {
630
            logMetacat.error(e.getClass() + ": " + e.getMessage());
631
            System.out.println("Error in ResourceHandler.handle(): " + e.getClass() + ": " + e.getMessage());
632
            e.printStackTrace();
633
        }
634
    }
635
    
636
    /**
637
     * handle the /replicate action
638
     * @param httpVerb
639
     * @param request
640
     * @param response
641
     * @throws Exception
642
     */
643
    private void replicate(int httpVerb, HttpServletRequest request, HttpServletResponse response)
644
        throws Exception
645
    {
646
        if(httpVerb == POST)
647
        {
648
            System.out.println("in POST replicate()");
649
            /*InputStream is = request.getInputStream();
650
            String input = IOUtils.toString(is);
651
            System.out.println("input: " + input);
652
            is = IOUtils.toInputStream(input);*/
653
            
654
            File tmpDir = getTempDirectory();
655
            File tmpSMFile = new File(tmpDir + 
656
                    ".sysmeta." + new Date().getTime() + ".tmp");
657
            System.out.println("temp dir: " + tmpDir.getAbsolutePath());
658
            MultipartRequestResolver mrr = new MultipartRequestResolver(
659
                    tmpDir.getAbsolutePath(), 1000000000, 0);
660
            MultipartRequest mr = mrr.resolveMultipart(request);
661
            Map<String, File> files = mr.getMultipartFiles();
662
            Iterator keys = files.keySet().iterator();
663
            while(keys.hasNext())
664
            {
665
                String key = (String)keys.next();
666
                System.out.println("files key: " + key);
667
                System.out.println("files value: " + files.get(key));
668
            }
669
            
670
            Map<String, List<String>> params = mr.getMultipartParameters();
671
            keys = params.keySet().iterator();
672
            while(keys.hasNext())
673
            {
674
                String key = (String)keys.next();
675
                System.out.println("params key: " + key);
676
                System.out.println("params value: " + params.get(key));
677
            }
678
            
679
            //File f = files.get("sysmeta");
680
            //the files are not being keyed by the part name, but rather the filename
681
            File f = files.get(files.keySet().iterator().next());
682
            
683
            System.out.println("file: " + f.getAbsolutePath());
684
            String sourceNode = params.get("sourceNode").get(0);
685
            System.out.println("sourceNode: " + sourceNode);
686
            FileInputStream fis = new FileInputStream(f);
687
            
688
            //lookup the id in the registry
689
            URL url = new URL("http://cn.dataone.org/cn/node");
690
            InputStream urlis = url.openStream();
691
            Map<String,String> m = NodeListParser.parseNodeListFile(urlis);
692
            String nodeUrl = m.get(sourceNode);
693
            System.out.println("sourceNodeId: " + sourceNode);
694
            System.out.println("resolved sourceNodeUrl: " + nodeUrl);
695
            
696
            if(nodeUrl == null)
697
            {
698
                response.setStatus(500);
699
                response.getOutputStream().write(("Member Node id " + 
700
                        sourceNode + " not found in node registry.").getBytes());
701
                response.getOutputStream().close();
702
            }
703
            
704
            //respond to cn with 200/OK
705
            //String s;
706
            //s = "sysmeta: " + IOUtils.toString(fis);
707
            //s += "\n\n";
708
            response.setStatus(200);
709
            //response.getOutputStream().write(("sourceNode: " + sourceNode + "\n\n").getBytes());
710
            //response.getOutputStream().write(("s: " + s).getBytes());
711
            OutputStream out = response.getOutputStream();
712
            out.write("OK\n".getBytes());
713
            out.write(("sourceNodeId: " + sourceNode + "\n").getBytes());
714
            out.write(("sourceNodeUrl: " + nodeUrl + "\n").getBytes());
715
            out.close();
716
            
717
            //parse the systemMetadata
718
            SystemMetadata sm = (SystemMetadata)deserializeServiceType(SystemMetadata.class, fis);
719
            NodeReference nr = sm.getOriginMemberNode();
720
            nr.setValue(sourceNode);
721
            sm.setOriginMemberNode(nr);
722
            //get the document
723
            AuthToken token = new AuthToken(sessionId);
724
            MNode mnode = new MNode(nodeUrl);
725
            //get the doc from the remote host
726
            InputStream docStream = mnode.get(new AuthToken("public"), sm.getIdentifier());
727
            File outputTmpFile = getTempFile();
728
            System.out.println("wrote xml file to " + outputTmpFile.getAbsolutePath());
729
            FileOutputStream outputTmpFileStream = new FileOutputStream(outputTmpFile);
730
            IOUtils.copy(docStream, outputTmpFileStream);
731
            
732
            //verify checksum
733
            System.out.println("verifying checksum");
734
            Checksum sourceFileChecksum = ServiceTypeUtil.checksum(new FileInputStream(outputTmpFile), 
735
                    sm.getChecksum().getAlgorithm());
736
            
737
            String cs1 = sm.getChecksum().getValue();
738
            String cs2 = sourceFileChecksum.getValue();
739
            System.out.println("original checksum: " + cs1);
740
            System.out.println(" created checksum: " + cs2);
741
            
742
            if(!cs1.equals(cs2))
743
            {
744
                System.out.println("ERROR: Checksums do not match!");
745
            }
746
            
747
            //insert the document in local db
748
            //System.out.println("creating new doc");
749
            //CrudService.getInstance().create(token, 
750
            //        sm.getIdentifier(), new FileInputStream(outputTmpFile), sm);
751
            //call cn.setReplicationStatus(guid, COMPLETE)
752
            
753
        }
754
    }
755
    
756
    /**
757
     * create the root node registry response.  
758
     * @throws JiBXException
759
     * @throws IOException
760
     */
761
    private void createNodeResponse() 
762
        throws JiBXException, IOException
763
    {
764
        String nodeName = null;
765
        String nodeId = null;
766
        String nodeUrl = null;
767
        String nodeDesc = null;
768
        String nodeType = null;
769
        
770
        try
771
        {
772
            nodeId = PropertyService.getProperty("dataone.memberNodeId");
773
            nodeName = PropertyService.getProperty("dataone.nodeName");
774
            nodeUrl = SystemUtil.getContextURL() + "/d1/";
775
            nodeDesc = PropertyService.getProperty("dataone.nodeDescription");
776
            nodeType = PropertyService.getProperty("dataone.nodeType");
777
        }
778
        catch(PropertyNotFoundException pnfe)
779
        {
780
            logMetacat.error("createNodeResponse: " +
781
                    "property not found: " + pnfe.getMessage());
782
        }
783
        
784
        NodeList nl = new NodeList();
785
        Node n = new Node();
786
        NodeReference nr = new NodeReference();
787
        nr.setValue(nodeId);
788
        n.setIdentifier(nr);
789
        n.setBaseURL(nodeUrl);
790
        n.setDescription(nodeDesc);
791
        n.setName(nodeName + " -- WAR version WARVERSION");
792
        n.setType(NodeType.convert(nodeType));
793
        
794
        //create the services
795
        Service mnCrud03 = new Service();
796
        mnCrud03.setName("Metacat MN_Crud Services Version 0.3");
797
        mnCrud03.setVersion("0.3");
798
        
799
        Service mnCrud04 = new Service();
800
        mnCrud04.setName("Metacat MN_Crud Services Version 0.4");
801
        mnCrud04.setVersion("0.4");
802
        
803
        Service mnCrud09 = new Service();
804
        mnCrud09.setName("Metacat MN_Crud Services Version 0.9");
805
        mnCrud09.setVersion("0.9");
806
        
807
        Service mnReplication03 = new Service();
808
        mnReplication03.setName("Metcat MN_Replication Version 0.3");
809
        mnReplication03.setVersion("0.3");
810
        
811
        Service mnHealth04 = new Service();
812
        mnHealth04.setName("Metacat MN_Health Version 0.4");
813
        mnHealth04.setVersion("0.4");
814
        
815
        Service mnHealth06 = new Service();
816
        mnHealth06.setName("Metacat MN_Health Version 0.6");
817
        mnHealth06.setVersion("0.6");
818
        
819
        Service mnAuthentication07 = new Service();
820
        mnAuthentication07.setName("Metacat MN_Authentication Version 0.7");
821
        mnAuthentication07.setVersion("0.7");
822
        
823
        Service mnAuthorization07 = new Service();
824
        mnAuthorization07.setName("Metacat MN_Authorization Version 0.7");
825
        mnAuthorization07.setVersion("0.7");
826
        
827
                                    //name, rest, implemented
828
        mnCrud03.addMethod(getServiceMethod("MN_crud.get()", "/object/<guid>", true));
829
        mnCrud03.addMethod(getServiceMethod("MN_crud.getSystemMetadata()", "/meta/<guid>", true));
830
        mnCrud04.addMethod(getServiceMethod("MN_crud.create()", "/object/<guid>", true));
831
        mnCrud04.addMethod(getServiceMethod("MN_crud.update()", "/object/<guid>", true));
832
        mnCrud09.addMethod(getServiceMethod("MN_crud.delete()", "/object/<guid>", true));
833
        mnCrud03.addMethod(getServiceMethod("MN_crud.describe()", "/object/<guid>", true));
834
        mnCrud03.addMethod(getServiceMethod("MN_crud.getChecksum()", "/checksum/<guid>", true));
835
        mnCrud03.addMethod(getServiceMethod("MN_crud.getLogRecords()", "/log", true));
836
        mnReplication03.addMethod(getServiceMethod("MN_replication.listObjects()", "/object", true));
837
        mnReplication03.addMethod(getServiceMethod("MN_replication.replicate()", "/object", true));
838
        mnHealth04.addMethod(getServiceMethod("MN_health.ping()", "/health/ping", false));
839
        mnHealth04.addMethod(getServiceMethod("MN_health.getObjectStatistics()", "/monitor/object/<guid>", false));
840
        mnHealth06.addMethod(getServiceMethod("MN_health.getStatus()", "/health/status", false));
841
        mnAuthentication07.addMethod(getServiceMethod("MN_authentication.login()", "/account/login", false));
842
        mnAuthentication07.addMethod(getServiceMethod("MN_authentication.logout()", "/account/logout", false));
843
        mnAuthorization07.addMethod(getServiceMethod("MN_authorization.isAuthorized()", "/isAuthorized/<guid>", false));
844
        
845
        Services ss = new Services();
846
        ss.addService(mnCrud03);
847
        ss.addService(mnCrud04);
848
        ss.addService(mnCrud09);
849
        ss.addService(mnReplication03);
850
        ss.addService(mnHealth04);
851
        ss.addService(mnHealth06);
852
        ss.addService(mnAuthentication07);
853
        ss.addService(mnAuthorization07);
854
        nl.addNode(n);
855
        response.setContentType("text/xml");
856
        response.setStatus(200);
857
        serializeServiceType(NodeList.class, nl, response.getOutputStream());
858
    }
859
    
860
    /**
861
     * MN_crud.describe()
862
     * http://mule1.dataone.org/ArchitectureDocs/mn_api_crud.html#MN_crud.describe
863
     * @param guid
864
     */
865
    private void describeObject(String guid)
866
    {
867
        Logger logMetacat = Logger.getLogger(ResourceHandler.class);
868
        OutputStream out = null;
869
        try
870
        {
871
            out = response.getOutputStream();
872
        }
873
        catch(Exception e)
874
        {
875
            logMetacat.error("Error getting output stream in ResourceHandler.describeObject: " + e.getClass() + ": " + e.getMessage());
876
            return;
877
        }
878
        response.setStatus(200);
879
        response.setContentType("text/xml");
880
        AuthToken token = new AuthToken(sessionId);
881
        CrudService cs = CrudService.getInstance();
882
        Identifier id = new Identifier();
883
        id.setValue(guid);
884
        try
885
        {
886
            DescribeResponse dr = cs.describe(token, id);
887
            DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SZ");
888
            response.addHeader("guid", guid);
889
            response.addHeader("checksum", dr.getDataONE_Checksum().getValue());
890
            response.addHeader("checksum_algorithm", dr.getDataONE_Checksum().getAlgorithm().name());
891
            response.addHeader("content_length", dr.getContent_Length() + "");
892
            response.addHeader("last_modified", dateFormat.format(dr.getLast_Modified()));
893
            response.addHeader("format", dr.getDataONE_ObjectFormat().toString());
894
        }
895
        catch(InvalidRequest ir)
896
        {
897
            serializeException(ir, out);
898
        }
899
        catch(NotImplemented ni)
900
        {
901
            serializeException(ni, out);
902
        }
903
        catch(NotAuthorized na)
904
        {
905
            serializeException(na, out);
906
        }
907
        catch(ServiceFailure sf)
908
        {
909
            serializeException(sf, out);
910
        }
911
        catch(NotFound nf)
912
        {
913
            serializeException(nf, out);
914
        }
915
        catch(InvalidToken it)
916
        {
917
            serializeException(it, out);
918
        }
919
    }
920
    
921
    /**
922
     * get the logs from the CrudService based on passed params.  Available 
923
     * params are token, fromDate, toDate, event.  See 
924
     * http://mule1.dataone.org/ArchitectureDocs/mn_api_crud.html#MN_crud.getLogRecords
925
     * for more info
926
     */
927
    private void getLog()
928
    {
929
        OutputStream out = null;
930
        try
931
        {
932
            out = response.getOutputStream();
933
            response.setStatus(200);
934
            response.setContentType("text/xml");
935
            AuthToken token = new AuthToken(sessionId);
936
            String fromDateS = params.get("fromDate")[0];
937
            System.out.println("param fromDateS: " + fromDateS);
938
            Date fromDate = null;
939
            String toDateS = params.get("toDate")[0];
940
            System.out.println("param toDateS: " + toDateS);
941
            Date toDate = null;
942
            String eventS = params.get("event")[0];
943
            Event event = null;
944
            if(fromDateS != null)
945
            {
946
                //fromDate = dateFormat.parse(fromDateS);
947
                fromDate = parseDateAndConvertToGMT(fromDateS);
948
            }
949
            if(toDateS != null)
950
            {
951
                //toDate = dateFormat.parse(toDateS);
952
                toDate = parseDateAndConvertToGMT(toDateS);
953
            }
954
            if(eventS != null)
955
            {
956
                event = Event.convert(eventS);
957
            }
958
            System.out.println("fromDate: " + fromDate + " toDate: " + toDate);
959
            
960
            System.out.println("calling crudservice.getLogRecords");
961
            Log log = CrudService.getInstance().getLogRecords(token, fromDate, toDate, event);
962
            serializeServiceType(Log.class, log, out);
963
        }
964
        catch(Exception e)
965
        {
966
            String msg = "Could not get logs from CrudService: " + e.getClass() + ": " + e.getMessage();
967
            response.setStatus(500);
968
            ServiceFailure sf = new ServiceFailure("1490", msg);
969
            logMetacat.error(msg);
970
            e.printStackTrace();
971
            serializeException(sf, out);
972
        }
973
    }
974
    
975
    /**
976
     *  copies request parameters to a hashtable which is given as argument to native metacathandler functions  
977
     */
978
    private void initParams() {
979

    
980
        String name = null;
981
        String[] value = null;
982
        Enumeration paramlist = request.getParameterNames();
983
        while (paramlist.hasMoreElements()) {
984
            name = (String) paramlist.nextElement();
985
            value = request.getParameterValues(name);
986
            params.put(name, value);
987
        }
988
    }
989

    
990
    /**
991
     * 
992
     * Load user details of metacat session from the request 
993
     * 
994
     */
995
    private void loadSessionData()
996
      throws Exception
997
    {
998
        SessionData sessionData = RequestUtil.getSessionData(request);
999
        try
1000
        {
1001
            username = null;
1002
            password = null;
1003
            groupNames = null;
1004
            sessionId = null;
1005
            
1006
            boolean validSession = false;
1007
            SessionService ss = SessionService.getInstance();
1008
            System.out.println("sessionData: " + sessionData);
1009
            if(sessionData == null)
1010
            {
1011
                username = "public";
1012
                sessionId = "0";
1013
                System.out.println("sessiondata is null.  Creating a public session.");
1014
                return;
1015
            }
1016
            
1017
            System.out.println("username: " + sessionData.getUserName());
1018
            System.out.println("sessionid: " + sessionData.getId());
1019
            //validate the session
1020
            if(ss.isSessionRegistered(sessionData.getId()) && 
1021
               !(sessionData.getUserName().equals("public") || sessionData.getId().equals("0")))
1022
            {
1023
                validSession = true;
1024
            }
1025
            
1026
            if(validSession)
1027
            {
1028
                //if the session is valid, set these variables
1029
                username = sessionData.getUserName();
1030
                password = sessionData.getPassword();
1031
                groupNames = sessionData.getGroupNames();
1032
                sessionId = sessionData.getId();
1033
                System.out.println("setting sessionid to " + sessionId);
1034
                System.out.println("username: " + username);
1035
            }
1036
            
1037
            //if the session is not valid or the username is null, set
1038
            //username to public
1039
            if (username == null) 
1040
            {
1041
                System.out.println("setting username to public.");
1042
                username = "public";
1043
            }
1044
        }
1045
        catch(Exception e)
1046
        {
1047
            e.printStackTrace();
1048
            throw new Exception("Could not load the session data: " + e.getClass() + ": " + e.getMessage());
1049
        }
1050
    }
1051

    
1052
    /**
1053
     *  Earthgrid API > Identifier Service > isRegistered Function : 
1054
     *  calls MetacatHandler > handleIdIsRegisteredAction
1055
     * @param guid
1056
     * @throws IOException
1057
     */
1058
    private void isRegistered(String guid) throws IOException
1059
    {
1060
        
1061
        // Look up the localId for this guid
1062
        IdentifierManager im = IdentifierManager.getInstance();
1063
        String localId = "";
1064
        try {
1065
            localId = im.getLocalId(guid);
1066
        } catch (McdbDocNotFoundException e) {
1067
            // TODO: Need to return the proper DataONE exception
1068
        }
1069
        
1070
        params.put("docid", new String[] { localId });
1071
        PrintWriter out = response.getWriter();
1072
        response.setStatus(200);
1073
        response.setContentType("text/xml");
1074
        handler.handleIdIsRegisteredAction(out, params, response);
1075
        out.close();
1076
    }
1077

    
1078
    /**
1079
     * Earthgrid API > Identifier Service > getAllDocIds Function : 
1080
     * calls MetacatHandler > handleGetAllDocidsAction
1081
     * @throws IOException
1082
     */
1083
    private void getAllDocIds() throws IOException {
1084
        PrintWriter out = response.getWriter();
1085
        response.setStatus(200);
1086
        response.setContentType("text/xml");
1087
        handler.handleGetAllDocidsAction(out, params, response);
1088
        out.close();
1089
    }
1090

    
1091
    /**
1092
     * Earthgrid API > Identifier Service > getNextRevision Function : 
1093
     * calls MetacatHandler > handleGetRevisionAndDocTypeAction
1094
     * @param guid
1095
     * @throws IOException
1096
     */
1097
    private void getNextRevision(String guid) throws IOException 
1098
    {
1099
        params.put("docid", new String[] { guid });
1100
        PrintWriter out = response.getWriter();
1101
        response.setStatus(200);
1102
        response.setContentType("text/xml");
1103
        //handler.handleGetRevisionAndDocTypeAction(out, params);
1104

    
1105
        try {
1106
            // Make sure there is a docid
1107
            if (guid == null || guid.equals("")) {
1108
                throw new Exception("User didn't specify docid!");
1109
            }
1110

    
1111
            // Look up the localId for this guid
1112
            IdentifierManager im = IdentifierManager.getInstance();
1113
            String localId = "";
1114
            try {
1115
                localId = im.getLocalId(guid);
1116
            } catch (McdbDocNotFoundException e) {
1117
                // TODO: Need to return the proper DataONE exception
1118
            }
1119
           
1120
            // Create a DBUtil object
1121
            DBUtil dbutil = new DBUtil();
1122
            // Get a rev and doctype
1123
            String revAndDocType = dbutil
1124
                    .getCurrentRevisionAndDocTypeForGivenDocument(localId);
1125
            int revision = Integer.parseInt(revAndDocType.split(";")[0]) + 1;
1126

    
1127
            out.println("<?xml version=\"1.0\"?>");
1128
            out.print("<next-revision>");
1129
            out.print(revision);
1130
            out.print("</next-revision>");
1131

    
1132
        } catch (Exception e) {
1133
            // Handle exception
1134
            response.setStatus(500);
1135
            out.println("<?xml version=\"1.0\"?>");
1136
            out.println("<error>");
1137
            out.println(e.getClass() + ": " + e.getMessage());
1138
            out.println("</error>");
1139
        }
1140

    
1141
        out.close();
1142
    }
1143

    
1144
    /**
1145
     * Earthgrid API > Identifier Service > getNextObject Function : 
1146
     * calls MetacatHandler > handleGetMaxDocidAction
1147
     * @throws IOException
1148
     */
1149
    private void getNextObject() throws IOException {
1150
        PrintWriter out = response.getWriter();
1151
        response.setStatus(200);
1152
        response.setContentType("text/xml");
1153
        handler.handleGetMaxDocidAction(out, params, response);
1154
        out.close();
1155
    }
1156

    
1157
    /**
1158
     * Implements REST version of DataONE CRUD API --> get
1159
     * @param guid ID of data object to be read
1160
     */
1161
    private void getObject(String guid) {
1162
        CrudService cs = CrudService.getInstance();
1163
        cs.setParamsFromRequest(request);
1164
        AuthToken token = new AuthToken(sessionId);
1165
        OutputStream out = null;
1166
        try {
1167
            out = response.getOutputStream();
1168
            response.setStatus(200);
1169
            
1170
            if(guid != null)
1171
            { //get a specific document                
1172
                Identifier id = new Identifier();
1173
                id.setValue(guid);
1174
                try
1175
                {
1176
                    if(token == null)
1177
                    {
1178
                        token = new AuthToken("Public");
1179
                    }
1180
                    SystemMetadata sm = cs.getSystemMetadata(token, id);
1181
                    
1182
                    //set the content type
1183
                    if(sm.getObjectFormat().getFmtid().getValue().trim().equals(
1184
                    		ObjectFormatCache.getFormat("text/csv").getFmtid().getValue()))
1185
                    {
1186
                        response.setContentType("text/csv");
1187
                        response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".csv");
1188
                    }
1189
                    else if(sm.getObjectFormat().getFmtid().getValue().trim().equals(
1190
                    		ObjectFormatCache.getFormat("text/plain").getFmtid().getValue()))
1191
                    {
1192
                        response.setContentType("text/plain");
1193
                        response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".txt");
1194
                    } 
1195
                    else if(sm.getObjectFormat().getFmtid().getValue().trim().equals(
1196
                    		ObjectFormatCache.getFormat("application/octet-stream").getFmtid().getValue()))
1197
                    {
1198
                        response.setContentType("application/octet-stream");
1199
                    }
1200
                    else
1201
                    {
1202
                        response.setContentType("text/xml");
1203
                        response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".xml");
1204
                    }
1205
                    
1206
                    InputStream data = cs.get(token, id);
1207
                    IOUtils.copyLarge(data, response.getOutputStream());
1208
                }
1209
                catch(InvalidToken it)
1210
                {
1211
                    response.setStatus(500);
1212
                    serializeException(it, out); 
1213
                }
1214
                catch(ServiceFailure sf)
1215
                {
1216
                    response.setStatus(500);
1217
                    serializeException(sf, out); 
1218
                }
1219
                catch(NotAuthorized na)
1220
                {
1221
                    response.setStatus(500);
1222
                    serializeException(na, out); 
1223
                }
1224
                catch(NotFound nf)
1225
                {
1226
                    response.setStatus(500);
1227
                    serializeException(nf, out); 
1228
                }
1229
                catch(NotImplemented ni)
1230
                {
1231
                    response.setStatus(500);
1232
                    serializeException(ni, out); 
1233
                }
1234
                catch(Exception e)
1235
                {
1236
                    response.setStatus(500);
1237
                    System.out.println("Error with Crud.get().  " +
1238
                            "If this is an 'Exception producing data' error, " +
1239
                            "go to CrudService.get() for better debugging.  " +
1240
                            "Here's the error: " + e.getClass() + ": " + e.getMessage());
1241
                    e.printStackTrace();
1242
                    ServiceFailure sf = new ServiceFailure("1030", 
1243
                            "IO Error in ResourceHandler.getObject: " + e.getClass() + ": " + e.getMessage());
1244
                    serializeException(sf, out); 
1245
                }
1246
            }
1247
            else
1248
            { //call listObjects with specified params
1249
                Date startTime = null;
1250
                Date endTime = null;
1251
                ObjectFormat objectFormat = null;
1252
                boolean replicaStatus = false;
1253
                int start = 0;
1254
                //TODO: make the max count into a const
1255
                int count = 1000;
1256
                Enumeration paramlist = request.getParameterNames();
1257
                while (paramlist.hasMoreElements()) 
1258
                { //parse the params and make the crud call
1259
                    String name = (String) paramlist.nextElement();
1260
                    String[] value = (String[])request.getParameterValues(name);
1261
                    /*for(int i=0; i<value.length; i++)
1262
                    {
1263
                        System.out.println("name: " + name + " value: " + value[i]);
1264
                    }*/
1265
                    if(name.equals("startTime") && value != null)
1266
                    {
1267
                        try
1268
                        {
1269
                          //startTime = dateFormat.parse(value[0]);
1270
                            startTime = parseDateAndConvertToGMT(value[0]);
1271
                        }
1272
                        catch(Exception e)
1273
                        {  //if we can't parse it, just don't use the startTime param
1274
                            System.out.println("Could not parse startTime: " + value[0]);
1275
                            startTime = null;
1276
                        }
1277
                    }
1278
                    else if(name.equals("endTime") && value != null)
1279
                    {
1280
                        try
1281
                        {
1282
                          //endTime = dateFormat.parse(value[0]);
1283
                            endTime = parseDateAndConvertToGMT(value[0]);
1284
                        }
1285
                        catch(Exception e)
1286
                        {  //if we can't parse it, just don't use the endTime param
1287
                            System.out.println("Could not parse endTime: " + value[0]);
1288
                            endTime = null;
1289
                        }
1290
                    }
1291
                    else if(name.equals("objectFormat") && value != null) 
1292
                    {
1293
                        objectFormat = ObjectFormatCache.getFormat(value[0]);
1294
                    }
1295
                    else if(name.equals("replicaStatus") && value != null)
1296
                    {
1297
                        if(value != null && 
1298
                           value.length > 0 && 
1299
                           (value[0].equals("true") || value[0].equals("TRUE") || value[0].equals("YES")))
1300
                        {
1301
                            replicaStatus = true;
1302
                        }
1303
                    }
1304
                    else if(name.equals("start") && value != null)
1305
                    {
1306
                        start = new Integer(value[0]).intValue();
1307
                    }
1308
                    else if(name.equals("count") && value != null)
1309
                    {
1310
                        count = new Integer(value[0]).intValue();
1311
                    }
1312
                }
1313
                //make the crud call
1314
                System.out.println("token: " + token + " startTime: " + startTime +
1315
                        " endtime: " + endTime + " objectFormat: " + 
1316
                        objectFormat + " replicaStatus: " + replicaStatus + 
1317
                        " start: " + start + " count: " + count);
1318
               
1319
                ObjectList ol = cs.listObjects(token, startTime, endTime, 
1320
                        objectFormat, replicaStatus, start, count);
1321
                
1322
                StringReader sr = new StringReader(ol.toString());                
1323
                out = response.getOutputStream();  
1324
                response.setStatus(200);
1325
                response.setContentType("text/xml");
1326
                // Serialize and write it to the output stream
1327
                
1328
                try {
1329
                    serializeServiceType(ObjectList.class, ol, out);
1330
                } catch (JiBXException e) {
1331
                    throw new ServiceFailure("1190", "Failed to serialize ObjectList: " + e.getMessage());
1332
                }
1333
            }
1334
        } catch (BaseException e) {
1335
                response.setStatus(500);
1336
                serializeException(e, out);
1337
        } catch (IOException e) {
1338
            e.printStackTrace();
1339
            response.setStatus(500);
1340
            ServiceFailure sf = new ServiceFailure("1030", 
1341
                    "IO Error in ResourceHandler.getObject: " + e.getMessage());
1342
            serializeException(sf, out); 
1343
        } catch(NumberFormatException ne) {
1344
            response.setStatus(500);
1345
            InvalidRequest ir = new InvalidRequest("1030", "Invalid format for parameter: " + ne.getMessage());
1346
            serializeException(ir, out);
1347
        } catch (Exception e) {
1348
            e.printStackTrace();
1349
            response.setStatus(500);
1350
            ServiceFailure sf = new ServiceFailure("1030", 
1351
                    "Exception " + e.getClass().getName() + " raised while handling listObjects request: " + 
1352
                    e.getMessage());
1353
            serializeException(sf, out);
1354
        }
1355
    }
1356
    
1357
    /**
1358
     * parse a date and return it in GMT if it ends with a 'Z'
1359
     * @param date
1360
     * @return
1361
     * @throws ParseException
1362
     */
1363
    private Date parseDateAndConvertToGMT(String date) throws ParseException
1364
    {
1365
        try
1366
        {   //the format we want
1367
            return dateFormat.parse(date);
1368
        }
1369
        catch(java.text.ParseException pe)
1370
        {   //try another legacy format
1371
            DateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'");
1372
            dateFormat2.setTimeZone(TimeZone.getTimeZone("GMT-0"));
1373
            return dateFormat2.parse(date);
1374
        }    
1375
    }
1376

    
1377
    /**
1378
     * Implements REST version of DataONE CRUD API --> getSystemMetadata
1379
     * @param guid ID of data object to be read
1380
     */
1381
    private void getSystemMetadataObject(String guid) {
1382
        CrudService cs = CrudService.getInstance();
1383
        cs.setParamsFromRequest(request);
1384
        AuthToken token = new AuthToken(sessionId);
1385
        OutputStream out = null;
1386
        try {
1387
            response.setContentType("text/xml");
1388
            response.setStatus(200);
1389
            out = response.getOutputStream();
1390
            Identifier id = new Identifier();
1391
            id.setValue(guid);
1392
            SystemMetadata sysmeta = cs.getSystemMetadata(token, id);
1393
            
1394
            // Serialize and write it to the output stream
1395
            try {
1396
                //TODO: look at the efficiency of this method.  The system metadata
1397
                //is read from metacat (in CrudService) as xml, then serialized
1398
                //to a SystemMetadat object, then returned here, then serizlized
1399
                //back to XML to be sent to the response.
1400
                serializeServiceType(SystemMetadata.class, sysmeta, out);
1401
            } catch (JiBXException e) {
1402
                throw new ServiceFailure("1190", "Failed to serialize SystemMetadata: " + e.getMessage());
1403
            }
1404
        } catch (BaseException e) {
1405
            response.setStatus(500);
1406
                serializeException(e, out);
1407
        } catch (IOException e) {
1408
            response.setStatus(500);
1409
            ServiceFailure sf = new ServiceFailure("1030", 
1410
                    "IO Error in ResourceHandler.getSystemMetadataObject: " + e.getMessage());
1411
            serializeException(sf, out);
1412
        } finally {
1413
            IOUtils.closeQuietly(out);
1414
        }
1415
    }
1416
    
1417
    /**
1418
     * serialize an object of type to out
1419
     * @param type the class of the object to serialize (i.e. SystemMetadata.class)
1420
     * @param object the object to serialize
1421
     * @param out the stream to serialize it to
1422
     * @throws JiBXException
1423
     */
1424
    private void serializeServiceType(Class type, Object object, OutputStream out)
1425
      throws JiBXException
1426
    {
1427
        ServiceTypeUtil.serializeServiceType(type, object, out);
1428
    }
1429
    
1430
    /**
1431
     * deserialize an object of type from is
1432
     * @param type the class of the object to serialize (i.e. SystemMetadata.class)
1433
     * @param is the stream to deserialize from
1434
     * @throws JiBXException
1435
     */
1436
    private Object deserializeServiceType(Class type, InputStream is)
1437
      throws JiBXException
1438
    {
1439
        return ServiceTypeUtil.deserializeServiceType(type, is);
1440
    }
1441
    
1442
    /**
1443
     * Earthgrid API > Query Service > Query Function : translates ecogrid query document to metacat query 
1444
     * then calls DBQuery > createResultDocument function and then again translate resultset to ecogrid resultset
1445
     * 
1446
     * NOTE:
1447
     *      This is the only method that uses EcoGrid classes for its implementation.  
1448
     *      It does so because it takes an EcoGrid Query as input, and outputs an
1449
     *      EcoGrid ResultSet document.  These documents are parsed by the auto-generated
1450
     *      EcoGrid classes from axis, and so we link to them here rather than re-inventing them.
1451
     *      This creates a circular dependency, because the Metacat classes are needed
1452
     *      to build the EcoGrid implementation, and the EcoGrid jars are needed to build this query()
1453
     *      method.  This circularity could be resolved by moving the EcoGrid classes
1454
     *      to Metacat directly.  As we transition away from EcoGrid SOAP methods in
1455
     *      favor of these REST interfaces, this circular dependency can be eliminated.
1456
     *        
1457
     * @throws Exception
1458
     */
1459
    private void query() throws Exception {
1460
        /*  This block commented out because of the EcoGrid circular dependency.
1461
         *  For now, query will not be supported until the circularity can be
1462
         *  resolved, probably by moving the ecogrid query syntax transformers
1463
         *  directly into the Metacat codebase.  MBJ 2010-02-03
1464
         
1465
        try {
1466
            EcogridQueryParser parser = new EcogridQueryParser(request
1467
                    .getReader());
1468
            parser.parseXML();
1469
            QueryType queryType = parser.getEcogridQuery();
1470
            EcogridJavaToMetacatJavaQueryTransformer queryTransformer = 
1471
                new EcogridJavaToMetacatJavaQueryTransformer();
1472
            QuerySpecification metacatQuery = queryTransformer
1473
                    .transform(queryType);
1474

    
1475
            DBQuery metacat = new DBQuery();
1476

    
1477
            boolean useXMLIndex = (new Boolean(PropertyService
1478
                    .getProperty("database.usexmlindex"))).booleanValue();
1479
            String xmlquery = "query"; // we don't care the query in resultset,
1480
            // the query can be anything
1481
            PrintWriter out = null; // we don't want metacat result, so set out null
1482

    
1483
            // parameter: queryspecification, user, group, usingIndexOrNot
1484
            StringBuffer result = metacat.createResultDocument(xmlquery,
1485
                    metacatQuery, out, username, groupNames, useXMLIndex);
1486

    
1487
            // create result set transfer       
1488
            String saxparser = PropertyService.getProperty("xml.saxparser");
1489
            MetacatResultsetParser metacatResultsetParser = new MetacatResultsetParser(
1490
                    new StringReader(result.toString()), saxparser, queryType
1491
                            .getNamespace().get_value());
1492
            ResultsetType records = metacatResultsetParser.getEcogridResult();
1493

    
1494
            System.out
1495
                    .println(EcogridResultsetTransformer.toXMLString(records));
1496
            response.setContentType("text/xml");
1497
            out = response.getWriter();
1498
            out.print(EcogridResultsetTransformer.toXMLString(records));
1499

    
1500
        } catch (Exception e) {
1501
            e.printStackTrace();
1502
        }*/
1503
        response.setContentType("text/xml");
1504
        response.setStatus(501);
1505
        PrintWriter out = response.getWriter();
1506
        out.print("<error>Query operation not yet supported by Metacat.</error>");
1507
        out.close();
1508
    }
1509
    
1510
    private String streamToString(InputStream is)
1511
    throws IOException
1512
    {
1513
        return IOUtil.toString(is);
1514
    }
1515

    
1516
    private InputStream stringToStream(String s)
1517
    throws IOException
1518
    {
1519
        ByteArrayInputStream bais = new ByteArrayInputStream(s.getBytes(MetaCatServlet.DEFAULT_ENCODING));
1520
        return bais;
1521
    }
1522
    
1523
    /**
1524
     * locate the boundary marker for an MMP
1525
     * @param is
1526
     * @return
1527
     * @throws IOException
1528
     */
1529
    protected static String[] findBoundaryString(InputStream is)
1530
        throws IOException
1531
    {
1532
        String[] endResult = new String[2];
1533
        String boundary = "";
1534
        String searchString = "boundary=";
1535
        boolean doneWithCurrentArray = false;
1536
        byte[] b = new byte[1024];
1537
        int numbytes = is.read(b, 0, 1024);
1538

    
1539
        while(numbytes != -1)
1540
        {
1541
            String s = new String(b, 0, numbytes);
1542
            int searchStringIndex = s.indexOf(searchString);
1543
            
1544
            if(s.indexOf("\"", searchStringIndex + searchString.length() + 1) == -1)
1545
            { //the end of the boundary is in the next byte array
1546
                boundary = s.substring(searchStringIndex + searchString.length() + 1, s.length());
1547
            }
1548
            else if(!boundary.startsWith("--"))
1549
            { //we can read the whole boundary from this byte array
1550
                boundary = s.substring(searchStringIndex + searchString.length() + 1, 
1551
                    s.indexOf("\"", searchStringIndex + searchString.length() + 1));
1552
                boundary = "--" + boundary;
1553
                endResult[0] = boundary;
1554
                endResult[1] = s.substring(s.indexOf("\"", searchStringIndex + searchString.length() + 1) + 1,
1555
                        s.length());
1556
                break;
1557
            }
1558
            else
1559
            { //we're now reading the 2nd byte array to get the rest of the boundary
1560
                searchString = "\"";
1561
                searchStringIndex = s.indexOf(searchString);
1562
                boundary += s.substring(0, searchStringIndex);
1563
                boundary = "--" + boundary;
1564
                endResult[0] = boundary;
1565
                endResult[1] = s.substring(s.indexOf("\"", searchStringIndex + searchString.length() + 1) + 1,
1566
                        s.length());
1567
                break;
1568
            }
1569
        }
1570
        System.out.println("boundary is: '" + boundary + "'");
1571
        return endResult;
1572
    }
1573
    
1574
    /**
1575
     * return the directory where temp files are stored
1576
     * @return
1577
     */
1578
    private static File getTempDirectory()
1579
    {
1580
        File tmpDir = null;
1581
        Logger logMetacat = Logger.getLogger(ResourceHandler.class);
1582
        try
1583
        {
1584
            tmpDir = new File(PropertyService.getProperty("application.tempDir"));
1585
        }
1586
        catch(PropertyNotFoundException pnfe)
1587
        {
1588
            logMetacat.error("ResourceHandler.writeMMPPartstoFiles: " +
1589
                    "application.tmpDir not found.  Using /tmp instead.");
1590
            tmpDir = new File("/tmp");
1591
        }
1592
        return tmpDir;
1593
    }
1594
    
1595
    /**
1596
     * return a tmp file with a given name
1597
     * @param name
1598
     * @return
1599
     */
1600
    private static File getTempFile(String name)
1601
    {
1602
        File tmpDir = getTempDirectory();
1603
        File f = new File(tmpDir, name);
1604
        return f;
1605
    }
1606
    
1607
    /**
1608
     * return a temp file with a default name
1609
     * @return
1610
     */
1611
    private static File getTempFile()
1612
    {
1613
        return getTempFile(new Date().getTime() + ".tmp");
1614
    }
1615
    
1616
    /**
1617
     * Earthgrid API > Put Service >Put Function : calls MetacatHandler > handleInsertOrUpdateAction 
1618
     * 
1619
     * @param guid - ID of data object to be inserted or updated.  If action is update, the pid
1620
     *               is the existing pid.  If insert, the pid is the new one
1621
     * @throws IOException
1622
     */
1623
    private void putObject(String pid, String action) {
1624
        System.out.println("ResourceHandler: putObject with pid " + pid);
1625
        logMetacat.debug("Entering putObject: " + pid + "/" + action);
1626
        OutputStream out = null;
1627
        try {
1628
            out = response.getOutputStream();
1629
            response.setStatus(200);
1630
            response.setContentType("text/xml");
1631
        } catch (IOException e1) {
1632
            logMetacat.error("Could not get the output stream for writing in putObject");
1633
        }
1634
        try {
1635
            
1636
            // Read the incoming data from its Mime Multipart encoding
1637
            logMetacat.debug("Disassembling MIME multipart form");
1638
            InputStream object = null;
1639
            InputStream sysmeta = null;
1640
            Map<String, List<String>> multipartparams;
1641
            
1642
            try
1643
            {
1644
                //String req = IOUtils.toString(request.getInputStream());
1645
                //System.out.println("request: " + req);
1646
                //InputStream reqStr = IOUtils.toInputStream(req);
1647
                InputStream reqStr = request.getInputStream();
1648
                
1649
                //handle MMP inputs
1650
                File tmpDir = getTempDirectory();
1651
                File tmpSMFile = new File(tmpDir + 
1652
                        ".sysmeta." + new Date().getTime() + ".tmp");
1653
                System.out.println("temp dir: " + tmpDir.getAbsolutePath());
1654
                MultipartRequestResolver mrr = new MultipartRequestResolver(
1655
                        tmpDir.getAbsolutePath(), 1000000000, 0);
1656
                MultipartRequest mr = mrr.resolveMultipart(request);
1657
                System.out.println("resolved multipart request");
1658
                Map<String, File> files = mr.getMultipartFiles();
1659
                if(files == null)
1660
                {
1661
                    throw new ServiceFailure("1202", "create/update must have multipart files with names 'object' and 'sysmeta'");
1662
                }
1663
                System.out.println("got multipart files");
1664
                
1665
                if(files.keySet() == null)
1666
                {
1667
                    System.out.println("No file keys in MMP request.");
1668
                    throw new ServiceFailure("1202", "No file keys found in MMP.  " +
1669
                            "create/update must have multipart files with names 'object' and 'sysmeta'");
1670
                }
1671

    
1672
		// for logging purposes, dump out the key-value pairs that constitute the request
1673
		// 3 types exist: request params, multipart params, and multipart files
1674
                Iterator it = files.keySet().iterator();
1675
                System.out.println("iterating through request parts: " + it);
1676
                while(it.hasNext())
1677
                {
1678
                    String key = (String)it.next();
1679
                    System.out.println("files key: " + key);
1680
                    System.out.println("files value: " + files.get(key));
1681
                }
1682
                
1683
                multipartparams = mr.getMultipartParameters();
1684
                it = multipartparams.keySet().iterator();
1685
                while(it.hasNext())
1686
                {
1687
                    String key = (String)it.next();
1688
                    System.out.println("multipartparams key: " + key);
1689
                    System.out.println("multipartparams value: " + multipartparams.get(key));
1690
                }
1691
                
1692
                it = params.keySet().iterator();
1693
                while(it.hasNext())
1694
                {
1695
                    String key = (String)it.next();
1696
                    System.out.println("param key: " + key);
1697
                    System.out.println("param value: " + params.get(key));
1698
                }
1699
		System.out.println("done iterating the request...");
1700

    
1701
                File smFile = files.get("sysmeta");
1702
		if (smFile == null) 
1703
		    throw new InvalidRequest("1102", "Missing the required file-part 'sysmeta' from the multipart request.");
1704
                System.out.println("smFile: " + smFile.getAbsolutePath());
1705
                sysmeta = new FileInputStream(smFile);
1706
                File objFile = files.get("object");
1707
		if (objFile == null) 
1708
		    throw new InvalidRequest("1102", "Missing the required file-part 'object' from the multipart request.");
1709

    
1710
                System.out.println("objectfile: " + objFile.getAbsolutePath());
1711
                object = new FileInputStream(objFile);
1712
                
1713
                /*String obj = IOUtils.toString(object);
1714
                String sm = IOUtils.toString(sysmeta);
1715
                System.out.println("object: " + obj);
1716
                System.out.println("sm: " + sm);
1717
                object = IOUtils.toInputStream(obj);
1718
                sysmeta = IOUtils.toInputStream(sm);*/
1719
                
1720
            }
1721
            catch(org.apache.commons.fileupload.FileUploadException fue)
1722
            {
1723
                throw new ServiceFailure("1202", "Could not upload MMP files: " + fue.getMessage());
1724
            }
1725
            catch(IOException ioe)
1726
            {
1727
                throw new ServiceFailure("1202", 
1728
                        "IOException when processing Mime Multipart: " + ioe.getMessage());
1729
            }
1730
            catch(Exception e)
1731
            {
1732
                throw new ServiceFailure("1202", "Error handling MMP upload: " + e.getClass() + ": " + e.getMessage());
1733
            }
1734
            
1735
            if ( action.equals(FUNCTION_NAME_INSERT)) { //handle inserts
1736

    
1737
                // Check if the objectId exists
1738
                IdentifierManager im = IdentifierManager.getInstance();
1739
                if (im.identifierExists(pid)) {
1740
                    throw new IdentifierNotUnique("1000", "Identifier is already in use: " + pid);
1741
                }
1742

    
1743
                logMetacat.debug("Commence creation...");
1744
                IBindingFactory bfact =
1745
                    BindingDirectory.getFactory(SystemMetadata.class);
1746
                IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
1747
                SystemMetadata smd = (SystemMetadata) uctx.unmarshalDocument(sysmeta, null);
1748

    
1749
                CrudService cs = CrudService.getInstance();
1750
                AuthToken token = new AuthToken(sessionId); 
1751
                cs.setParamsFromRequest(request);
1752
                Identifier id = new Identifier();
1753
                id.setValue(pid);
1754
                System.out.println("creating object with pid " + id.getValue());
1755
                Identifier rId = cs.create(token, id, object, smd);
1756
                serializeServiceType(Identifier.class, rId, out);
1757
                
1758
            } else if (action.equals(FUNCTION_NAME_UPDATE)) { //handle updates
1759

    
1760
            	// Check if the objectId exists
1761
                IdentifierManager im = IdentifierManager.getInstance();
1762
                if (!im.identifierExists(pid)) {
1763
                    throw new NotFound("1280", "The pid you are trying to update does not exist: " + pid);
1764
                }
1765
                // check that the newPid parameter was provided and it doesn't exist
1766
                if(multipartparams.get("newPid") == null)
1767
                    throw new InvalidRequest("1202", "'newPid' must be contained in the request parameters.");
1768
                String newPidString = multipartparams.get("newPid").get(0);
1769
                if (im.identifierExists(newPidString)) 
1770
                    throw new IdentifierNotUnique("1220", "Identifier is already in use: " + newPidString);
1771
               
1772
                
1773
                Identifier newPid = new Identifier();
1774
                Identifier obsoletedPid = new Identifier();
1775
                newPid.setValue(newPidString);
1776
                obsoletedPid.setValue(pid);
1777
               
1778
            	
1779
                CrudService cs = CrudService.getInstance();
1780
                AuthToken token = new AuthToken(sessionId);
1781

    
1782
                logMetacat.debug("Commence update...");
1783
                
1784
                //get the systemmetadata
1785
                IBindingFactory bfact =
1786
                	BindingDirectory.getFactory(SystemMetadata.class);
1787
                IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
1788
                SystemMetadata smd = (SystemMetadata) uctx.unmarshalDocument(sysmeta, null);
1789

    
1790
                cs.setParamsFromRequest(request);
1791
                Identifier rId = cs.update(token, newPid, object, obsoletedPid, smd);
1792
                serializeServiceType(Identifier.class, rId, out);
1793
            } else {
1794
                throw new InvalidRequest("1000", "Operation must be create or update.");
1795
            }
1796
            
1797
            //clean up the MMP files
1798
            //parts.get("systemmetadata").delete();
1799
            //parts.get("object").delete();
1800
        } catch (NotAuthorized e) {
1801
            response.setStatus(500);
1802
            serializeException(e, out);
1803
        } catch (InvalidToken e) {
1804
            response.setStatus(500);
1805
            serializeException(e, out);
1806
        } catch (ServiceFailure e) {
1807
            response.setStatus(500);
1808
            serializeException(e, out);
1809
        } catch (NotFound e) {
1810
            response.setStatus(500);
1811
            serializeException(e, out);
1812
        } catch (IdentifierNotUnique e) {
1813
            response.setStatus(500);
1814
            serializeException(e, out);
1815
        } catch (UnsupportedType e) {
1816
            response.setStatus(500);
1817
            serializeException(e, out);
1818
        } catch (InsufficientResources e) {
1819
            response.setStatus(500);
1820
            serializeException(e, out);
1821
        } catch (InvalidSystemMetadata e) {
1822
            response.setStatus(500);
1823
            serializeException(e, out);
1824
        } catch (NotImplemented e) {
1825
            response.setStatus(500);
1826
            serializeException(e, out);
1827
        } catch (InvalidRequest e) {
1828
            response.setStatus(500);
1829
            serializeException(e, out);
1830
        } /*catch (MessagingException e) {
1831
            ServiceFailure sf = new ServiceFailure("1000", e.getMessage());
1832
            serializeException(sf, out);
1833
        } catch (IOException e) {
1834
            response.setStatus(500);
1835
            ServiceFailure sf = new ServiceFailure("1000", e.getMessage());
1836
            serializeException(sf, out);
1837
        }*/ catch (JiBXException e) {
1838
            response.setStatus(500);
1839
            e.printStackTrace(System.out);
1840
            InvalidSystemMetadata ism = new InvalidSystemMetadata("1080", e.getMessage());
1841
            serializeException(ism, out);
1842
        }
1843
    }
1844

    
1845
    /**
1846
     * Handle delete 
1847
     * @param guid ID of data object to be deleted
1848
     * @throws IOException
1849
     */
1850
    private void deleteObject(String guid) throws IOException 
1851
    {
1852
        // Look up the localId for this global identifier
1853
        System.out.println("!!!!!!!!!!!!!!!!!deleting object " + guid);
1854
        IdentifierManager im = IdentifierManager.getInstance();
1855
        String localId = "";
1856
        OutputStream out = response.getOutputStream();
1857
        response.setStatus(200);
1858
        try {
1859
            localId = im.getLocalId(guid);
1860
        } catch (McdbDocNotFoundException e) {
1861
            NotFound nf = new NotFound("1340", "Document with guid " + guid + " not found.");
1862
            response.setStatus(404);
1863
            serializeException(nf, out);
1864
        }
1865
       
1866
        AuthToken token = new AuthToken(sessionId);
1867
        CrudService cs = CrudService.getInstance();
1868
        Identifier id = new Identifier();
1869
        id.setValue(guid);
1870
        try
1871
        {
1872
            System.out.println("Calling delete");
1873
            cs.delete(token, id);
1874
            serializeServiceType(Identifier.class, id, out);
1875
        } 
1876
        catch (NotAuthorized e) {
1877
            response.setStatus(500);
1878
            serializeException(e, out);
1879
        } catch (InvalidToken e) {
1880
            response.setStatus(500);
1881
            serializeException(e, out);
1882
        } catch (ServiceFailure e) {
1883
            response.setStatus(500);
1884
            serializeException(e, out);
1885
        } catch (NotImplemented e) {
1886
            response.setStatus(500);
1887
            serializeException(e, out);
1888
        } catch (InvalidRequest e) {
1889
            response.setStatus(500);
1890
            serializeException(e, out);
1891
        } catch(NotFound e) {
1892
            response.setStatus(500);
1893
            serializeException(e, out);
1894
        } catch(JiBXException e) {
1895
            response.setStatus(500);
1896
            serializeException(new ServiceFailure("1350", "JiBXException: " + e.getMessage()), out);
1897
        }
1898
        out.close();
1899
    }
1900
    
1901
    /**
1902
     * set the access perms on a document
1903
     * @throws IOException
1904
     */
1905
    private void setaccess() throws Exception
1906
    {
1907
        try
1908
        {
1909
            String guid = params.get("guid")[0];
1910
            Identifier id = new Identifier();
1911
            id.setValue(guid);
1912
            AuthToken token = new AuthToken(sessionId);
1913
            String principal = params.get("principal")[0];
1914
            String permission = params.get("permission")[0];
1915
            String permissionType = params.get("permissionType")[0];
1916
            String permissionOrder = params.get("permissionOrder")[0];
1917
            String setSystemMetadata = params.get("setsystemmetadata")[0];
1918
            boolean ssm = false;
1919
            if(setSystemMetadata.equals("true") || setSystemMetadata.equals("TRUE") ||
1920
                    setSystemMetadata.equals("yes"))
1921
            {
1922
                ssm = true;
1923
            }
1924
            CrudService cs = CrudService.getInstance();
1925
            //TODO: remove the setsystemmetadata param and set this so the systemmetadata always gets set
1926
            cs.setAccess(token, id, principal, permission, permissionType, permissionOrder, ssm);
1927
        }
1928
        catch(Exception e)
1929
        {
1930
            response.setStatus(500);
1931
            printError("Error setting access in ResourceHandler: " + e.getClass() + ": " + e.getMessage(), response);
1932
            throw e;
1933
        }
1934
    }
1935

    
1936
    /**
1937
     * Earthgrid API > Authentication Service > Login Function : calls MetacatHandler > handleLoginAction
1938
     * 
1939
     * @throws IOException
1940
     */
1941
    private void login() throws IOException {
1942
        PrintWriter out = response.getWriter();
1943
        response.setStatus(200);
1944
        response.setContentType("text/xml");
1945
        handler.handleLoginAction(out, params, request, response);
1946
        out.close();
1947
    }
1948

    
1949
    /**
1950
     * Earthgrid API > Authentication Service > Logout Function : calls MetacatHandler > handleLogoutAction
1951
     * 
1952
     * @throws IOException
1953
     */
1954
    private void logout() throws IOException {
1955
        PrintWriter out = response.getWriter();
1956
        response.setStatus(200);
1957
        response.setContentType("text/xml");
1958
        handler.handleLogoutAction(out, params, request, response);
1959
        out.close();
1960
    }
1961

    
1962
    /**
1963
     * Prints xml response
1964
     * @param message Message to be displayed
1965
     * @param response Servlet response that xml message will be printed 
1966
     * */
1967
    private void printError(String message, HttpServletResponse response) {
1968
        try {
1969
            logMetacat.error("ResourceHandler: Printing error to servlet response: " + message);
1970
            PrintWriter out = response.getWriter();
1971
            response.setContentType("text/xml");
1972
            out.println("<?xml version=\"1.0\"?>");
1973
            out.println("<error>");
1974
            out.println(message);
1975
            out.println("</error>");
1976
            out.close();
1977
        } catch (IOException e) {
1978
            e.printStackTrace();
1979
        }
1980
    }
1981
    
1982
    /**
1983
     * serialize a D1 exception using jibx
1984
     * @param e
1985
     * @param out
1986
     */
1987
    private void serializeException(BaseException e, OutputStream out) {
1988
        // TODO: Use content negotiation to determine which return format to use
1989
        response.setContentType("text/xml");
1990
        response.setStatus(e.getCode());
1991
        
1992
        logMetacat.error("ResourceHandler: Serializing exception with code " + e.getCode() + ": " + e.getMessage());
1993
        e.printStackTrace();
1994
        
1995
        try {
1996
            IOUtils.write(e.serialize(BaseException.FMT_XML), out);
1997
        } catch (IOException e1) {
1998
            logMetacat.error("Error writing exception to stream. " 
1999
                    + e1.getMessage());
2000
        }
2001
    }
2002
    
2003
    /**
2004
     * create a new ServiceMethod declaration
2005
     * @param name
2006
     * @param rest
2007
     * @param implemented
2008
     * @return
2009
     */
2010
    private ServiceMethod getServiceMethod(String name, String rest, boolean implemented)
2011
    {
2012
        ServiceMethod sm = new ServiceMethod();
2013
        sm.setImplemented(implemented);
2014
        sm.setName(name);
2015
        sm.setRest(rest);
2016
        return sm;
2017
    }
2018

    
2019
    /**
2020
     * Register System Metadata without data or metadata object
2021
     * @param pid identifier for System Metadata entry
2022
     */
2023
	private void registerSystemMetadata(String pid) {
2024
		logMetacat.debug("Entering registerSystemMetadata: " + pid);
2025
		OutputStream out = null;
2026
		try {
2027
			out = response.getOutputStream();
2028
			response.setStatus(200);
2029
			response.setContentType("text/xml");
2030
		} catch (IOException e1) {
2031
			logMetacat.error("Could not get the output stream for writing in putObject");
2032
		}
2033
		try {
2034

    
2035
			// Read the incoming data from its Mime Multipart encoding
2036
			logMetacat.debug("Disassembling MIME multipart form");
2037
			InputStream sysmeta = null;
2038
			Map<String, List<String>> multipartparams;
2039

    
2040
			try {
2041

    
2042
				// handle MMP inputs
2043
				File tmpDir = getTempDirectory();
2044

    
2045
				logMetacat.debug("temp dir: " + tmpDir.getAbsolutePath());
2046
				MultipartRequestResolver mrr = new MultipartRequestResolver(
2047
						tmpDir.getAbsolutePath(), 1000000000, 0);
2048
				MultipartRequest mr = mrr.resolveMultipart(request);
2049
				logMetacat.debug("resolved multipart request");
2050
				Map<String, File> files = mr.getMultipartFiles();
2051
				if (files == null) {
2052
					throw new ServiceFailure("1202",
2053
							"register meta must have multipart file with name 'sysmeta'");
2054
				}
2055
				logMetacat.debug("got multipart files");
2056

    
2057
				if (files.keySet() == null) {
2058
					logMetacat.error("No file keys in MMP request.");
2059
					throw new ServiceFailure(
2060
							"1202",
2061
							"No file keys found in MMP.  "
2062
									+ "register meta must have multipart file with name 'sysmeta'");
2063
				}
2064

    
2065
				// for logging purposes, dump out the key-value pairs that
2066
				// constitute the request
2067
				// 3 types exist: request params, multipart params, and
2068
				// multipart files
2069
				Iterator it = files.keySet().iterator();
2070
				logMetacat.debug("iterating through request parts: " + it);
2071
				while (it.hasNext()) {
2072
					String key = (String) it.next();
2073
					logMetacat.debug("files key: " + key);
2074
					logMetacat.debug("files value: " + files.get(key));
2075
				}
2076

    
2077
				multipartparams = mr.getMultipartParameters();
2078
				it = multipartparams.keySet().iterator();
2079
				while (it.hasNext()) {
2080
					String key = (String) it.next();
2081
					logMetacat.debug("multipartparams key: " + key);
2082
					logMetacat.debug("multipartparams value: "
2083
							+ multipartparams.get(key));
2084
				}
2085

    
2086
				it = params.keySet().iterator();
2087
				while (it.hasNext()) {
2088
					String key = (String) it.next();
2089
					logMetacat.debug("param key: " + key);
2090
					logMetacat.debug("param value: " + params.get(key));
2091
				}
2092
				logMetacat.debug("done iterating the request...");
2093

    
2094
				File smFile = files.get("sysmeta");
2095
				if (smFile == null) {
2096
					throw new InvalidRequest("1102",
2097
							"Missing the required file-part 'sysmeta' from the multipart request.");
2098
				}
2099
				logMetacat.debug("smFile: " + smFile.getAbsolutePath());
2100
				sysmeta = new FileInputStream(smFile);
2101

    
2102
			} catch (org.apache.commons.fileupload.FileUploadException fue) {
2103
				throw new ServiceFailure("1202", "Could not upload MMP files: "
2104
						+ fue.getMessage());
2105
			} catch (IOException ioe) {
2106
				throw new ServiceFailure("1202",
2107
						"IOException when processing Mime Multipart: "
2108
								+ ioe.getMessage());
2109
			} catch (Exception e) {
2110
				throw new ServiceFailure("1202", "Error handling MMP upload: "
2111
						+ e.getClass() + ": " + e.getMessage());
2112
			}
2113

    
2114
			// Check if the objectId exists
2115
			IdentifierManager im = IdentifierManager.getInstance();
2116
			if (im.identifierExists(pid)) {
2117
				throw new IdentifierNotUnique("1000",
2118
						"Identifier is already in use: " + pid);
2119
			}
2120

    
2121
			logMetacat.debug("Commence creation...");
2122
			IBindingFactory bfact = BindingDirectory
2123
					.getFactory(SystemMetadata.class);
2124
			IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
2125
			SystemMetadata systemMetadata = (SystemMetadata) uctx
2126
					.unmarshalDocument(sysmeta, null);
2127

    
2128
			// TODO: get session
2129
			Session session = null;
2130
			Identifier guid = new Identifier();
2131
			guid.setValue(pid);
2132
			logMetacat.debug("registering system metadata with pid "
2133
					+ guid.getValue());
2134
			boolean result = CNCoreImpl.getInstance().registerSystemMetaData(
2135
					session, guid, systemMetadata);
2136
			serializeServiceType(Boolean.class, result, out);
2137

    
2138
		} catch (NotAuthorized e) {
2139
			response.setStatus(500);
2140
			serializeException(e, out);
2141
		} catch (ServiceFailure e) {
2142
			response.setStatus(500);
2143
			serializeException(e, out);
2144
		} catch (IdentifierNotUnique e) {
2145
			response.setStatus(500);
2146
			serializeException(e, out);
2147
		} catch (NotImplemented e) {
2148
			response.setStatus(500);
2149
			serializeException(e, out);
2150
		} catch (InvalidRequest e) {
2151
			response.setStatus(500);
2152
			serializeException(e, out);
2153
		} catch (JiBXException e) {
2154
			response.setStatus(500);
2155
			e.printStackTrace(System.out);
2156
			InvalidSystemMetadata ism = new InvalidSystemMetadata("1080", e
2157
					.getMessage());
2158
			serializeException(ism, out);
2159
		}
2160
	}
2161

    
2162
}
(4-4/5)