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.*;
26
import java.net.URL;
27
import java.util.*;
28

    
29
import javax.mail.BodyPart;
30
import javax.mail.MessagingException;
31
import javax.mail.internet.MimeMultipart;
32
import javax.servlet.ServletContext;
33
import javax.servlet.http.HttpServletRequest;
34
import javax.servlet.http.HttpServletResponse;
35
import java.text.DateFormat;
36
import java.text.ParseException;
37
import java.text.ParsePosition;
38
import java.text.SimpleDateFormat;
39

    
40

    
41
import org.apache.commons.httpclient.util.DateParser;
42
import org.apache.commons.io.IOUtils;
43
import org.apache.log4j.Logger;
44
import org.apache.maven.artifact.ant.shaded.IOUtil;
45
import org.dataone.mimemultipart.MultipartResponseHandler;
46
import org.dataone.service.NodeListParser;
47
import org.dataone.service.exceptions.BaseException;
48
import org.dataone.service.exceptions.IdentifierNotUnique;
49
import org.dataone.service.exceptions.InsufficientResources;
50
import org.dataone.service.exceptions.InvalidRequest;
51
import org.dataone.service.exceptions.InvalidSystemMetadata;
52
import org.dataone.service.exceptions.InvalidToken;
53
import org.dataone.service.exceptions.NotAuthorized;
54
import org.dataone.service.exceptions.NotImplemented;
55
import org.dataone.service.exceptions.ServiceFailure;
56
import org.dataone.service.exceptions.UnsupportedType;
57
import org.dataone.service.exceptions.NotFound;
58
import org.dataone.service.types.*;
59
import org.jibx.runtime.BindingDirectory;
60
import org.jibx.runtime.IBindingFactory;
61
import org.jibx.runtime.IMarshallingContext;
62
import org.jibx.runtime.IUnmarshallingContext;
63
import org.jibx.runtime.JiBXException;
64

    
65
import edu.ucsb.nceas.metacat.DBUtil;
66
import edu.ucsb.nceas.metacat.IdentifierManager;
67
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
68
import edu.ucsb.nceas.metacat.MetaCatServlet;
69
import edu.ucsb.nceas.metacat.MetacatHandler;
70
import edu.ucsb.nceas.metacat.client.InsufficientKarmaException;
71
import edu.ucsb.nceas.metacat.dataone.CrudService;
72
import edu.ucsb.nceas.metacat.dataone.HealthService;
73
import edu.ucsb.nceas.metacat.properties.PropertyService;
74
import edu.ucsb.nceas.metacat.service.SessionService;
75
import edu.ucsb.nceas.metacat.util.RequestUtil;
76
import edu.ucsb.nceas.metacat.util.SessionData;
77
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
78

    
79
import org.dataone.service.streaming.util.StreamUtil;
80

    
81
import com.gc.iotools.stream.is.InputStreamFromOutputStream;
82
import com.oreilly.servlet.multipart.FilePart;
83
import com.oreilly.servlet.multipart.MultipartParser;
84
import com.oreilly.servlet.multipart.ParamPart;
85
import com.oreilly.servlet.multipart.Part;
86
/**
87
 * 
88
 * Implements Earthgrid REST API to Metacat <br/><br/> 
89
 * 
90
 * <ul>
91
 * <li>
92
 * <h3> EarthGrid Query Service</h3>
93
 * <ul><li>
94
 * <h3>Get & Authenticated Get:</h3> 
95
 * is equal to Metacat's read action and returns a data file having
96
 * the specified <doc-id> in the resource path. For authenticated Get service, a session id must be provided 
97
 * in the query string. <br/><br/>
98
 * 
99
 * <b>REST URL:</b> <code>GET, [context-root]/object/[doc-id]?sessionid=[sessionid] </code><br/>
100
 * <b>Returns:</b> data file <br/><br/>
101
 * </li>
102
 * 
103
 * <li>
104
 * <h3>Query & Authenticated Query:</h3> 
105
 * Metacat's equivalent is squery action but this function 
106
 * receives a Earthgrid query document and returns Earthgrid resultset document by transforming those documents
107
 * to Metacat's equivalents by the means of Metacat Implementation in Earthgrid library. For authenticated Query service 
108
 * a session id must be provided in the query string. See Earthgrid (a.k.a. Ecogrid) project for XSD files of 
109
 * query and resultset documents<br/><br/>
110
 * 
111
 * <b>REST URL:</b> <code>POST, [context-root]/object?sessionid=[sessionid]</code>    <br/>
112
 * <b>POST Data:</b> Earthgrid query document , Content-type: <code>text/xml</code><br/>
113
 * <b>Returns:</b> Earthgrid resultset document<br/><br/>
114
 * 
115
 * </li>
116
 * </ul>
117
 * 
118
 * </li>
119
 * 
120
 * <li>
121
 * <h3> EarthGrid Authentication Service</h3>
122
 * <ul><li>
123
 * <h3>Login: </h3> 
124
 * Receives username and password parameters in POST data and 
125
 * returns SessionId (in XML format) or failure message and uses MetacatHandler's handleLoginAction function<br/><br/>
126
 *  
127
 * <b>REST URL:</b> <code>POST, [context-root]/session?op=login</code> <br/>
128
 * <b>POST Data:</b> username=[username]&password=[password], Content-type: <code>application/x-www-form-urlencoded</code>
129
 * <b>Returns:</b> sessionId in XML format<br/><br/>
130
 * </li>
131
 * 
132
 * <li>
133
 * <h3>Logout: </h3> 
134
 * Receives session Id parameters in querystring and returns xml message, calls 
135
 * MetacatHandler's handleLogoutAction function<br/><br/>
136
 *  
137
 * <b>REST URL:</b> <code>GET, [context-root]/session?op=logout&sessionid=[sessionid]</code>   <br/>
138
 * <b>Returns:</b> message in XML format<br/><br/>
139
 * </li>
140
 * </ul>
141
 * 
142
 * <li>
143
 * <h3>EarthGrid Put Service</h3>
144
 * 
145
 * <ul>
146
 * <li><h3>Update/Insert: </h3>     
147
 * <br/>
148
 * <b>REST URL:</b> <code>PUT, [context-root]/object/[doc-id]?op={update|insert}&sessionid=[sessionid]</code>   <br/>
149
 * <b>POST Data:</b> document object, Content-type: <code>text/xml</code><br/>
150
 * <b>Returns:</b> message in XML format<br/><br/>
151
 * </li>
152
 * 
153
 * <li><h3>Delete: </h3>        
154
 * <br/>
155
 * <b>REST URL:</b> <code>DELETE, [context-root]/object/[doc-id]?sessionid=[sessionid]</code>   <br/>
156
 * <b>Returns:</b> message in XML format<br/><br/>
157
 * </li>
158

    
159
 * </ul>
160
 * </li>
161
 * 
162
 * <li>
163
 * <h3>EarthGrid Identifier Service</h3><br/>
164
 * 
165
 * <ul>
166
 * <li><h3>isRegistered: </h3>      <br/>
167
 * <b>REST URL:</b> <code>GET, [context-root]/identifier/[doc-id]?op=isregistered</code>   <br/>
168
 * <b>Returns:</b> message in XML format<br/><br/>
169
 * </li>
170

    
171
 * <li><h3>getAllDocIds:</h3>       <br/>       
172
 * <b>REST URL:</b> <code>GET, [context-root]/identifier?op=getalldocids</code>   <br/>
173
 * <b>Returns:</b> document id list in XML format<br/><br/>
174
 * </li>
175
 * 
176
 * <li><h3>addLSID Function:</h3> 
177
 * Metacat does not support this function       <br/>
178
 * <b>REST URL:</b> <code>PUT, [context-root]/identifier/[doc-id]</code>   <br/>
179
 * <b>Returns:</b> error message in XML format<br/><br/>
180
 * </li>
181
 * 
182
 * <li><h3>getNextRevision:</h3>        <br/>
183
 * <b>REST URL:</b> <code>GET, [context-root]/identifier/[doc-id]?op=getnextrevision</code>   <br/>
184
 * <b>Returns:</b> message in XML format<br/><br/>
185
 * </li>
186
 * 
187
 * <li><h3>getNextObject:</h3>      <br/>
188
 * <b>REST URL:</b> <code>GET, [context-root]/identifier?op=getnextobject&scope=[scope]</code>   <br/>
189
 * <b>Returns:</b> message in XML format<br/><br/>
190
 * </li>
191
 * 
192
 * </li>
193
 * </ul>
194
 * 
195
 */
196
public class ResourceHandler {
197

    
198
    /**HTTP Verb GET*/
199
    public static final byte GET = 1;
200
    /**HTTP Verb POST*/
201
    public static final byte POST = 2;
202
    /**HTTP Verb PUT*/
203
    public static final byte PUT = 3;
204
    /**HTTP Verb DELETE*/
205
    public static final byte DELETE = 4;
206
    /**HTTP Verb HEAD*/
207
    public static final byte HEAD = 5;
208

    
209
    /*
210
     * API Resources
211
     */
212
    private static final String RESOURCE_OBJECTS = "object";
213
    private static final String RESOURCE_META = "meta";
214
    private static final String RESOURCE_SESSION = "session";
215
    private static final String RESOURCE_IDENTIFIER = "identifier";
216
    private static final String RESOURCE_LOG = "log";
217
    private static final String RESOURCE_CHECKSUM = "checksum";
218
    private static final String RESOURCE_MONITOR = "monitor";
219
    private static final String RESOURCE_BASE_URL = "d1";
220
    private static final String RESOURCE_REPLICATE = "replicate";
221

    
222
    /*
223
     * API Functions used as URL parameters
224
     */
225
    private static final String FUNCTION_KEYWORD = "op";
226
    private static final String FUNCTION_NAME_LOGIN = "login";
227
    private static final String FUNCTION_NAME_LOGOUT = "logout";
228
    private static final String FUNCTION_NAME_SET_ACCESS = "setaccess";
229
    private static final String FUNCTION_NAME_ISREGISTERED = "isregistered";
230
    private static final String FUNCTION_NAME_GETALLDOCS = "getalldocids";
231
    private static final String FUNCTION_NAME_GETNEXTREV = "getnextrevision";
232
    private static final String FUNCTION_NAME_GETNEXTOBJ = "getnextobject";
233
    private static final String FUNCTION_NAME_INSERT = "insert";
234
    private static final String FUNCTION_NAME_UPDATE = "update";
235
    private static final String FUNCTION_NAME_GENERATE_MISSING_SYSTEM_METADATA = "generatemissingsystemmetadata";
236

    
237
    private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
238
    
239
    private ServletContext servletContext;
240
    private Logger logMetacat;
241
    private MetacatHandler handler;
242
    private HttpServletRequest request;
243
    private HttpServletResponse response;
244
    private String username;
245
    private String password;
246
    private String sessionId;
247
    private String[] groupNames;
248

    
249
    private Hashtable<String, String[]> params;
250

    
251
    /**Initializes new instance by setting servlet context,request and response*/
252
    public ResourceHandler(ServletContext servletContext,
253
            HttpServletRequest request, HttpServletResponse response) {
254
        this.servletContext = servletContext;
255
        this.request = request;
256
        this.response = response;
257
    }
258

    
259
    /**
260
     * This function is called from REST APU servlet and handles each request to the servlet 
261
     * 
262
     * @param httpVerb (GET, POST, PUT or DELETE)
263
     */
264
    public void handle(byte httpVerb) {
265
        logMetacat = Logger.getLogger(ResourceHandler.class);
266
        try {
267
            String resource = request.getServletPath();
268
            if(resource.endsWith("d1/") || resource.endsWith("d1"))
269
            {
270
                resource = RESOURCE_BASE_URL;
271
            }
272
            else
273
            {
274
                //substring off the /d1/
275
                resource = resource.substring(resource.indexOf("d1/") + 3, resource.length());
276
                resource = resource.trim();
277
            }
278
            
279
            String verb = "";
280
            
281
            System.out.println("handling verb " + httpVerb + " request with resource '" + resource + "'");
282
            System.out.println("resource: '" + resource + "'");
283
            System.out.println("resource_monitor: '" + RESOURCE_MONITOR + "'");
284
            boolean status = false;
285
            loadSessionData();
286

    
287
            if (resource != null) {
288
                //resource = request.getServletPath().substring(1);
289

    
290
                params = new Hashtable<String, String[]>();
291
                initParams();
292

    
293
                Timer timer = new Timer();
294
                handler = new MetacatHandler(timer);
295

    
296
                if(resource.equals(RESOURCE_BASE_URL)) {
297
                    //node registry response
298
                    System.out.println("Using resource 'd1' (node registry response)");
299
                    createNodeResponse();
300
                    status = true;
301
                    
302
                } else if (resource.equals(RESOURCE_SESSION) && 
303
                        httpVerb == POST && 
304
                        params.get(FUNCTION_KEYWORD) != null) {
305
                    System.out.println("Using resource 'session'");
306
                    //System.out.println("function_keyword: " + params.get(FUNCTION_KEYWORD)[0]);
307
                    if (params.get(FUNCTION_KEYWORD)[0].equals(FUNCTION_NAME_LOGIN)) {
308
                        login();
309
                        status = true;
310
                    } else if (params.get(FUNCTION_KEYWORD)[0].equals(FUNCTION_NAME_LOGOUT)) {
311
                        logout();
312
                        status = true;
313
                    } else if (params.get(FUNCTION_KEYWORD)[0].equals(FUNCTION_NAME_SET_ACCESS)) {
314
                        setaccess();
315
                        status = true;
316
                        System.out.println("done setting access");
317
                    }
318
                } else if (resource.equals(RESOURCE_META)) {
319
                    System.out.println("Using resource 'meta'");
320
                    if(params != null && params.get(FUNCTION_KEYWORD) != null &&
321
                            params.get(FUNCTION_KEYWORD)[0].equals(FUNCTION_NAME_GENERATE_MISSING_SYSTEM_METADATA))
322
                    { //generate system metadata for any object that is
323
                        //a) not system metadata itself
324
                        //b) does not already have a system metadata id in the systemmetadata table
325
                        //c) not a BIN object (data)
326
                        //TODO: check if we need this anymore.  Might be superceded
327
                        //by MetacatPopulator
328
                        generateMissingSystemMetadata();
329
                        status = true;
330
                    }
331
                    else
332
                    {
333
                        String objectId = request.getPathInfo();
334
                        if (objectId != null && objectId.length() > 1) 
335
                        {
336
                            objectId = request.getPathInfo().substring(1);
337
                        }
338
                        getSystemMetadataObject(objectId);
339
                        status = true;
340
                    }
341

    
342
                } else if (resource.equals(RESOURCE_OBJECTS)) {
343
                    System.out.println("Using resource 'object'");
344
                    logMetacat.debug("D1 Rest: Starting resource processing...");
345
                    loadSessionData();
346

    
347
                    String objectId = request.getPathInfo();
348
                    if (objectId != null && objectId.length() > 1) 
349
                    {
350
                        objectId = request.getPathInfo().substring(1);
351
                    }
352
                    else
353
                    {
354
                        objectId = null;
355
                    }
356
                    
357
                    System.out.println("objectId in ReasourceHandler.handle: " + objectId);
358

    
359
                    logMetacat.debug("verb:" + httpVerb);
360

    
361
                    if (httpVerb == GET) {
362
                        getObject(objectId);
363
                        status = true;
364
                    } else if (httpVerb == POST) {
365
                        putObject(objectId, FUNCTION_NAME_INSERT);
366
                        status = true;
367
                    } else if (httpVerb == PUT) {
368
                        putObject(objectId, FUNCTION_NAME_UPDATE);
369
                        status = true;
370
                    } else if (httpVerb == DELETE) {
371
                        deleteObject(objectId);
372
                        status = true;
373
                    } else if (httpVerb == HEAD) {
374
                        describeObject(objectId);
375
                        status = true;
376
                    }
377
                    
378

    
379
                } else if (resource.equals(RESOURCE_IDENTIFIER)) {
380
                    System.out.println("Using resource 'identifier'");
381
                    String identifierId = request.getPathInfo();
382
                    if (identifierId != null && identifierId.length() > 1)
383
                        identifierId = request.getPathInfo().substring(1); //trim the slash
384

    
385
                    if (httpVerb == GET) {
386
                        String op = params.get(FUNCTION_KEYWORD)[0];
387
                        if (op.equals(FUNCTION_NAME_ISREGISTERED)) {
388
                            isRegistered(identifierId);
389
                            status = true;
390
                        } else if (op.equals(FUNCTION_NAME_GETALLDOCS)) {
391
                            getAllDocIds();
392
                            status = true;
393
                        } else if (op.equals(FUNCTION_NAME_GETNEXTREV)) {
394
                            getNextRevision(identifierId);
395
                            status = true;
396
                        } else if (op.equals(FUNCTION_NAME_GETNEXTOBJ)) {
397
                            getNextObject();
398
                            status = true;
399
                        } 
400

    
401
                    } else if (httpVerb == PUT) {
402
                        //Earthgrid API > Identifier Service > addLSID Function 
403
                        response.setStatus(501);
404
                        printError(
405
                                "This method is not supported by metacat.  To "
406
                                + "add a new LSID, add a document to metacat.",
407
                                response);
408
                        status = true;
409
                    }
410

    
411
                } else if (resource.equals(RESOURCE_LOG)) {
412
                    System.out.println("Using resource 'log'");
413
                    //handle log events
414
                    if(httpVerb == GET)
415
                    {
416
                        getLog();
417
                        status = true;
418
                    }
419
                    else
420
                    {
421
                        //change to D1 spec for specifying which http methods are allowed for a resource
422
                        response.setStatus(501);
423
                        printError("POST, PUT, DELETE is not supported for logs.", response);
424
                        status = true;
425
                    }
426

    
427
                } else if(resource.equals(RESOURCE_CHECKSUM)) {
428
                    System.out.println("Using resource 'checksum'");
429
                    //handle checksum requests
430
                    if(httpVerb == GET)
431
                    {
432
                        String guid = null;
433
                        String checksumAlgorithm = "MD5";
434
                    
435
                        try
436
                        {
437
                           guid = params.get("id")[0];
438
                        }
439
                        catch(Exception e)
440
                        {
441
                            throw new InvalidRequest("1402", "Incorrect parameters passed to getChecksum");
442
                        }
443
                        
444
                        Identifier guidid = new Identifier();
445
                        guidid.setValue(guid);
446
                        AuthToken token = new AuthToken(sessionId);
447
                        try
448
                        {
449
                            checksumAlgorithm = params.get("checksumAlgorithm")[0];
450
                        }
451
                        catch(Exception e)
452
                        {
453
                            //do nothing.  default to MD5
454
                        }
455
                        System.out.println("getting checksum for object " + guid +
456
                                " with algorithm " + checksumAlgorithm);
457
                        try
458
                        {
459
                            Checksum c = CrudService.getInstance().getChecksum(token, guidid, checksumAlgorithm);
460
                            System.out.println("got checksum " + c.getValue());
461
                            response.setStatus(200);
462
                            System.out.println("serializing response");
463
                            serializeServiceType(Checksum.class, c, response.getOutputStream());
464
                            System.out.println("done serializing response.");
465
                        }
466
                        catch(NotAuthorized na)
467
                        {
468
                            na.setDetail_code("1400");
469
                            serializeException(na, response.getOutputStream());
470
                        }
471
                        catch(NotFound nf)
472
                        {
473
                            nf.setDetail_code("1420");
474
                            serializeException(nf, response.getOutputStream());
475
                        }
476
                        catch(InvalidRequest ir)
477
                        {
478
                            ir.setDetail_code("1402");
479
                            serializeException(ir, response.getOutputStream());
480
                        }
481
                        catch(ServiceFailure sf)
482
                        {
483
                            sf.setDetail_code("1410");
484
                            serializeException(sf, response.getOutputStream());
485
                        }
486
                        catch(InvalidToken it)
487
                        {
488
                            it.setDetail_code("1430");
489
                            serializeException(it, response.getOutputStream());
490
                        }
491
                        status = true;
492
                    }
493
                } else if(resource.equals(RESOURCE_MONITOR)) {
494
                    //health monitoring calls
495
                    System.out.println("processing monitor request");
496
                    String pathInfo = request.getPathInfo();
497
                    if(httpVerb == GET)
498
                    {
499
                        System.out.println("verb is GET");
500
                        System.out.println("pathInfo is " + pathInfo);
501
                        pathInfo = pathInfo.substring(1);
502
                        HealthService hs = new HealthService(request, response);
503
                        if (pathInfo.toLowerCase().equals("ping")) {
504
                            System.out.println("processing ping request");
505
                            hs.ping();
506
                        } else if (pathInfo.toLowerCase().equals("status")) {
507
                            System.out.println("processing status request");
508
                            hs.getStatus();
509
                        } else if (pathInfo.toLowerCase().equals("object")) {
510
                            System.out.println("processing object request");
511
                            boolean day = false;
512
                            Identifier pid = null;
513
                            String url = null;
514
                            ObjectFormat of = null;
515
                            Date time = null;
516
                            
517
                            if(params.containsKey("day"))
518
                            {
519
                               day = true; 
520
                            }
521
                            if(params.containsKey("pid"))
522
                            {
523
                                String id = params.get("pid")[0];
524
                                pid = new Identifier();
525
                                pid.setValue(id);
526
                            }
527
                            if(params.containsKey("url"))
528
                            {
529
                                url = params.get("url")[0];
530
                            }
531
                            if(params.containsKey("format"))
532
                            {
533
                                String format = params.get("format")[0];
534
                                of = ObjectFormat.convert(format);
535
                            }
536
                            if(params.containsKey("time"))
537
                            {
538
                                String t = params.get("time")[0];
539
                                time = dateFormat.parse(t);
540
                            }
541
                            
542
                            hs.getObjectStatistics(day, pid, url, of, time);
543
                        } else if (pathInfo.toLowerCase().equals("event")) {
544
                            System.out.println("processing event request");
545
                            boolean day = false;
546
                            Identifier pid = null;
547
                            Date created = null;
548
                            ObjectFormat of = null;
549
                            Date time = null;
550
                            String ipAddress = null;
551
                            String event = null;
552
                            
553
                            if(params.containsKey("day"))
554
                            {
555
                               day = true; 
556
                            }
557
                            if(params.containsKey("pid"))
558
                            {
559
                                String id = params.get("pid")[0];
560
                                pid = new Identifier();
561
                                pid.setValue(id);
562
                            }
563
                            if(params.containsKey("created"))
564
                            {
565
                                String t = params.get("created")[0];
566
                                created = dateFormat.parse(t);
567
                            }
568
                            if(params.containsKey("format"))
569
                            {
570
                                String format = params.get("format")[0];
571
                                of = ObjectFormat.convert(format);
572
                            }
573
                            if(params.containsKey("eventtime"))
574
                            {
575
                                String t = params.get("eventtime")[0];
576
                                time = dateFormat.parse(t);
577
                            }
578
                            if(params.containsKey("ip_address"))
579
                            {
580
                                ipAddress = params.get("ip_address")[0];
581
                            }
582
                            if(params.containsKey("event"))
583
                            {
584
                                event = params.get("event")[0];
585
                            }
586
                            
587
                            hs.getOperationStatistics(day, pid, of, created, time, ipAddress, event);
588
                        }
589
                    }
590
                    status = true;
591
                } else if(resource.equals(RESOURCE_REPLICATE)) {
592
                    System.out.println("processing replicate request");
593
                    
594
                    if(httpVerb == POST)
595
                    {
596
                        InputStream is = request.getInputStream();
597
                        /*String input = IOUtils.toString(is);
598
                        System.out.println("input: " + input);
599
                        is = IOUtils.toInputStream(input);*/
600
                        
601
                        MultipartResponseHandler mpHandler = 
602
                            new MultipartResponseHandler(request, new File("/tmp/sysmeta"));
603
                        Hashtable parts = mpHandler.getParts();
604
                        File f = (File)parts.get("sysmeta");
605
                        String sourceNode = (String)parts.get("sourceNode");
606
                        FileInputStream fis = new FileInputStream(f);
607
                        String s;
608
                        s = "sysmeta: " + IOUtils.toString(fis);
609
                        s += "\n\n";
610
                        
611
                        
612
                        
613
                        //get the system metadata from the request
614
                       
615
                        /*String[] searchStrings = {
616
                                "Content-Disposition: attachment; name=sysmeta\n\n",
617
                                "Content-Disposition: form-data; name=sourceNode\n\n"};
618
                        String[] names = {
619
                                "systemmetadata",
620
                                "sourceNode"
621
                        };
622
                        InputStream is = request.getInputStream();
623
                        //Hashtable<String,File> mmpFiles = writeMMPPartsToFiles(is, searchStrings, names);
624
                        String s = IOUtils.toString(is);
625
                        System.out.println("s: " + s);*/
626
                        /*int startIndex = s.indexOf(searchStrings[0]);
627
                        startIndex = s.indexOf("\n\n", startIndex);
628
                        int endIndex = s.indexOf("\n--", startIndex);
629
                        System.out.println("startIndex: " + startIndex);
630
                        System.out.println("endIndex: " + endIndex);
631
                        String smStr = s.substring(startIndex, endIndex);
632
                        System.out.println("smStr: " + smStr);
633
                        SystemMetadata sm = (SystemMetadata)
634
                            deserializeServiceType(SystemMetadata.class, new ByteArrayInputStream(smStr.getBytes()));
635
                        //String nodeId = sm.getAuthoritativeMemberNode().getValue();
636
                        startIndex = s.indexOf(searchStrings[1], endIndex);
637
                        endIndex = s.indexOf("\n--", startIndex);
638
                        String sourceNode = s.substring(startIndex, endIndex);
639
                        System.out.println("sourceNode: " + sourceNode);
640
                        //lookup nodeId from the registry
641
                        URL url = new URL("http://cn.dataone.org/cn/node");
642
                        InputStream urlis = url.openStream();
643
                        Map<String,String> m = NodeListParser.parseNodeListFile(urlis);
644
                        String nodeUrl = m.get(sourceNode);
645
                        System.out.println("nodeUrl: " + nodeUrl);
646
                        if(nodeUrl == null)
647
                        {
648
                            response.setStatus(500);
649
                            response.getOutputStream().write(("Member Node id " + 
650
                                    sourceNode + " not found in node registry.").getBytes());
651
                            response.getOutputStream().close();
652
                        }
653
                        
654
                        //we at least have enough information to continue so
655
                        //tell the cn we're ok
656
                        //respond to cn with 200/OK*/
657
                        response.setStatus(200);
658
                        response.getOutputStream().write(("sourceNode: " + sourceNode + "\n\n").getBytes());
659
                        response.getOutputStream().write(("s: " + s).getBytes());
660
                        response.getOutputStream().close();
661
                        
662
                        //get the document
663
                        //verify checksum
664
                        //insert the document in local db
665
                        //call cn.setReplicationStatus(guid, COMPLETE)
666
                        
667
                        /*Questions:
668
                         * Call is now supposed to look like replicate(token, SystemMetadata, SourceNode)
669
                         * how is SystemMetadata encoded?  Multipart?
670
                         * 
671
                         * Is the token passed used to access MN_A?  How does MN_A
672
                         * know it's valid?
673
                         * 
674
                         * What exactly is happening when setReplicationStatus is called
675
                         * to the CN?  Which systemMetadata is being updated?  MN_A or MN_B or both?
676
                         * 
677
                         * 
678
                         * 
679
                         */
680
                        
681
                    }
682
                    
683
                    status = true;
684
                }
685
                    
686
                if (!status)
687
                {
688
                    response.setStatus(400);
689
                    printError("Incorrect parameters!", response);
690
                }
691
            } else {
692
                response.setStatus(400);
693
                printError("Incorrect resource!", response);
694
            }
695
        } catch (Exception e) {
696
            logMetacat.error(e.getMessage());
697
            e.printStackTrace();
698
        }
699
    }
700
    
701
    /**
702
     * create the root node registry response.  
703
     * @throws JiBXException
704
     * @throws IOException
705
     */
706
    private void createNodeResponse() 
707
        throws JiBXException, IOException
708
    {
709
        NodeList nl = new NodeList();
710
        Node n = new Node();
711
        NodeReference nr = new NodeReference();
712
        nr.setValue(request.getRequestURL().toString());
713
        n.setIdentifier(nr);
714
        n.setBaseURL(request.getRequestURL().toString());
715
        n.setDescription("Metacat DataONE Node");
716
        n.setName("Metacat WAR version WARVERSION");
717
        n.setType(NodeType.convert("mn"));
718
        
719
        //create the services
720
        Service mnCrud03 = new Service();
721
        mnCrud03.setName("Metacat MN_Crud Services Version 0.3");
722
        mnCrud03.setVersion("0.3");
723
        
724
        Service mnCrud04 = new Service();
725
        mnCrud04.setName("Metacat MN_Crud Services Version 0.4");
726
        mnCrud04.setVersion("0.4");
727
        
728
        Service mnCrud09 = new Service();
729
        mnCrud09.setName("Metacat MN_Crud Services Version 0.9");
730
        mnCrud09.setVersion("0.9");
731
        
732
        Service mnReplication03 = new Service();
733
        mnReplication03.setName("Metcat MN_Replication Version 0.3");
734
        mnReplication03.setVersion("0.3");
735
        
736
        Service mnHealth04 = new Service();
737
        mnHealth04.setName("Metacat MN_Health Version 0.4");
738
        mnHealth04.setVersion("0.4");
739
        
740
        Service mnHealth06 = new Service();
741
        mnHealth06.setName("Metacat MN_Health Version 0.6");
742
        mnHealth06.setVersion("0.6");
743
        
744
        Service mnAuthentication07 = new Service();
745
        mnAuthentication07.setName("Metacat MN_Authentication Version 0.7");
746
        mnAuthentication07.setVersion("0.7");
747
        
748
        Service mnAuthorization07 = new Service();
749
        mnAuthorization07.setName("Metacat MN_Authorization Version 0.7");
750
        mnAuthorization07.setVersion("0.7");
751
        
752
                                    //name, rest, implemented
753
        mnCrud03.addMethod(getServiceMethod("MN_crud.get()", "/object/<guid>", true));
754
        mnCrud03.addMethod(getServiceMethod("MN_crud.getSystemMetadata()", "/meta/<guid>", true));
755
        mnCrud04.addMethod(getServiceMethod("MN_crud.create()", "/object/<guid>", true));
756
        mnCrud04.addMethod(getServiceMethod("MN_crud.update()", "/object/<guid>", true));
757
        mnCrud09.addMethod(getServiceMethod("MN_crud.delete()", "/object/<guid>", true));
758
        mnCrud03.addMethod(getServiceMethod("MN_crud.describe()", "/object/<guid>", true));
759
        mnCrud03.addMethod(getServiceMethod("MN_crud.getChecksum()", "/checksum/<guid>", true));
760
        mnCrud03.addMethod(getServiceMethod("MN_crud.getLogRecords()", "/log", true));
761
        mnReplication03.addMethod(getServiceMethod("MN_replication.listObjects()", "/object", true));
762
        mnReplication03.addMethod(getServiceMethod("MN_replication.replicate()", "/object", true));
763
        mnHealth04.addMethod(getServiceMethod("MN_health.ping()", "/health/ping", false));
764
        mnHealth04.addMethod(getServiceMethod("MN_health.getObjectStatistics()", "/monitor/object/<guid>", false));
765
        mnHealth06.addMethod(getServiceMethod("MN_health.getStatus()", "/health/status", false));
766
        mnAuthentication07.addMethod(getServiceMethod("MN_authentication.login()", "/account/login", false));
767
        mnAuthentication07.addMethod(getServiceMethod("MN_authentication.logout()", "/account/logout", false));
768
        mnAuthorization07.addMethod(getServiceMethod("MN_authorization.isAuthorized()", "/isAuthorized/<guid>", false));
769
        
770
        Services ss = new Services();
771
        ss.addService(mnCrud03);
772
        ss.addService(mnCrud04);
773
        ss.addService(mnCrud09);
774
        ss.addService(mnReplication03);
775
        ss.addService(mnHealth04);
776
        ss.addService(mnHealth06);
777
        ss.addService(mnAuthentication07);
778
        ss.addService(mnAuthorization07);
779
        nl.addNode(n);
780
        response.setContentType("text/xml");
781
        response.setStatus(200);
782
        serializeServiceType(NodeList.class, nl, response.getOutputStream());
783
    }
784
    
785
    /**
786
     * MN_crud.describe()
787
     * http://mule1.dataone.org/ArchitectureDocs/mn_api_crud.html#MN_crud.describe
788
     * @param guid
789
     */
790
    private void describeObject(String guid)
791
    {
792
        Logger logMetacat = Logger.getLogger(ResourceHandler.class);
793
        OutputStream out = null;
794
        try
795
        {
796
            out = response.getOutputStream();
797
        }
798
        catch(Exception e)
799
        {
800
            logMetacat.error("Error getting output stream in ResourceHandler.describeObject: " + e.getMessage());
801
            return;
802
        }
803
        response.setStatus(200);
804
        response.setContentType("text/xml");
805
        AuthToken token = new AuthToken(sessionId);
806
        CrudService cs = CrudService.getInstance();
807
        Identifier id = new Identifier();
808
        id.setValue(guid);
809
        try
810
        {
811
            DescribeResponse dr = cs.describe(token, id);
812
            DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SZ");
813
            response.addHeader("guid", guid);
814
            response.addHeader("checksum", dr.getDataONE_Checksum().getValue());
815
            response.addHeader("checksum_algorithm", dr.getDataONE_Checksum().getAlgorithm().name());
816
            response.addHeader("content_length", dr.getContent_Length() + "");
817
            response.addHeader("last_modified", dateFormat.format(dr.getLast_Modified()));
818
            response.addHeader("format", dr.getDataONE_ObjectFormat().toString());
819
        }
820
        catch(InvalidRequest ir)
821
        {
822
            serializeException(ir, out);
823
        }
824
        catch(NotImplemented ni)
825
        {
826
            serializeException(ni, out);
827
        }
828
        catch(NotAuthorized na)
829
        {
830
            serializeException(na, out);
831
        }
832
        catch(ServiceFailure sf)
833
        {
834
            serializeException(sf, out);
835
        }
836
        catch(NotFound nf)
837
        {
838
            serializeException(nf, out);
839
        }
840
        catch(InvalidToken it)
841
        {
842
            serializeException(it, out);
843
        }
844
    }
845
    
846
    /**
847
     * get the logs from the CrudService based on passed params.  Available 
848
     * params are token, fromDate, toDate, event.  See 
849
     * http://mule1.dataone.org/ArchitectureDocs/mn_api_crud.html#MN_crud.getLogRecords
850
     * for more info
851
     */
852
    private void getLog()
853
    {
854
        OutputStream out = null;
855
        try
856
        {
857
            out = response.getOutputStream();
858
            response.setStatus(200);
859
            response.setContentType("text/xml");
860
            AuthToken token = new AuthToken(sessionId);
861
            String fromDateS = params.get("fromDate")[0];
862
            System.out.println("param fromDateS: " + fromDateS);
863
            Date fromDate = null;
864
            String toDateS = params.get("toDate")[0];
865
            System.out.println("param toDateS: " + toDateS);
866
            Date toDate = null;
867
            String eventS = params.get("event")[0];
868
            Event event = null;
869
            if(fromDateS != null)
870
            {
871
                //fromDate = dateFormat.parse(fromDateS);
872
                fromDate = parseDateAndConvertToGMT(fromDateS);
873
            }
874
            if(toDateS != null)
875
            {
876
                //toDate = dateFormat.parse(toDateS);
877
                toDate = parseDateAndConvertToGMT(toDateS);
878
            }
879
            if(eventS != null)
880
            {
881
                event = Event.convert(eventS);
882
            }
883
            System.out.println("fromDate: " + fromDate + " toDate: " + toDate);
884
            
885
            System.out.println("calling crudservice.getLogRecords");
886
            Log log = CrudService.getInstance().getLogRecords(token, fromDate, toDate, event);
887
            serializeServiceType(Log.class, log, out);
888
        }
889
        catch(Exception e)
890
        {
891
            String msg = "Could not get logs from CrudService: " + e.getMessage();
892
            response.setStatus(500);
893
            ServiceFailure sf = new ServiceFailure("1490", msg);
894
            logMetacat.error(msg);
895
            e.printStackTrace();
896
            serializeException(sf, out);
897
        }
898
    }
899
    
900
    /**
901
     *  copies request parameters to a hashtable which is given as argument to native metacathandler functions  
902
     */
903
    private void initParams() {
904

    
905
        String name = null;
906
        String[] value = null;
907
        Enumeration paramlist = request.getParameterNames();
908
        while (paramlist.hasMoreElements()) {
909
            name = (String) paramlist.nextElement();
910
            value = request.getParameterValues(name);
911
            params.put(name, value);
912
        }
913
    }
914

    
915
    /**
916
     * 
917
     * Load user details of metacat session from the request 
918
     * 
919
     */
920
    private void loadSessionData()
921
      throws Exception
922
    {
923
        SessionData sessionData = RequestUtil.getSessionData(request);
924
        try
925
        {
926
            username = null;
927
            password = null;
928
            groupNames = null;
929
            sessionId = null;
930
            
931
            boolean validSession = false;
932
            SessionService ss = SessionService.getInstance();
933
            System.out.println("sessionData: " + sessionData);
934
            if(sessionData == null)
935
            {
936
                username = "public";
937
                sessionId = "0";
938
                System.out.println("sessiondata is null.  Creating a public session.");
939
                return;
940
            }
941
            
942
            System.out.println("username: " + sessionData.getUserName());
943
            System.out.println("sessionid: " + sessionData.getId());
944
            //validate the session
945
            if(ss.isSessionRegistered(sessionData.getId()) && 
946
               !(sessionData.getUserName().equals("public") || sessionData.getId().equals("0")))
947
            {
948
                validSession = true;
949
            }
950
            
951
            if(validSession)
952
            {
953
                //if the session is valid, set these variables
954
                username = sessionData.getUserName();
955
                password = sessionData.getPassword();
956
                groupNames = sessionData.getGroupNames();
957
                sessionId = sessionData.getId();
958
                System.out.println("setting sessionid to " + sessionId);
959
                System.out.println("username: " + username);
960
            }
961
            
962
            //if the session is not valid or the username is null, set
963
            //username to public
964
            if (username == null) 
965
            {
966
                System.out.println("setting username to public.");
967
                username = "public";
968
            }
969
        }
970
        catch(Exception e)
971
        {
972
            e.printStackTrace();
973
            throw new Exception("Could not load the session data: " + e.getMessage());
974
        }
975
    }
976
    
977
    /**
978
     * generate missing system metadata for any science metadata objects
979
     * that don't already have it. https://trac.dataone.org/ticket/591
980
     * 
981
     * called with POST meta/?op=generatemissingsystemmetadata
982
     */
983
    private void generateMissingSystemMetadata()
984
    {
985
        AuthToken token = new AuthToken(sessionId);
986
        CrudService.getInstance().generateMissingSystemMetadata(token);
987
    }
988

    
989
    /**
990
     *  Earthgrid API > Identifier Service > isRegistered Function : 
991
     *  calls MetacatHandler > handleIdIsRegisteredAction
992
     * @param guid
993
     * @throws IOException
994
     */
995
    private void isRegistered(String guid) throws IOException
996
    {
997
        
998
        // Look up the localId for this guid
999
        IdentifierManager im = IdentifierManager.getInstance();
1000
        String localId = "";
1001
        try {
1002
            localId = im.getLocalId(guid);
1003
        } catch (McdbDocNotFoundException e) {
1004
            // TODO: Need to return the proper DataONE exception
1005
        }
1006
        
1007
        params.put("docid", new String[] { localId });
1008
        PrintWriter out = response.getWriter();
1009
        response.setStatus(200);
1010
        response.setContentType("text/xml");
1011
        handler.handleIdIsRegisteredAction(out, params, response);
1012
        out.close();
1013
    }
1014

    
1015
    /**
1016
     * Earthgrid API > Identifier Service > getAllDocIds Function : 
1017
     * calls MetacatHandler > handleGetAllDocidsAction
1018
     * @throws IOException
1019
     */
1020
    private void getAllDocIds() throws IOException {
1021
        PrintWriter out = response.getWriter();
1022
        response.setStatus(200);
1023
        response.setContentType("text/xml");
1024
        handler.handleGetAllDocidsAction(out, params, response);
1025
        out.close();
1026
    }
1027

    
1028
    /**
1029
     * Earthgrid API > Identifier Service > getNextRevision Function : 
1030
     * calls MetacatHandler > handleGetRevisionAndDocTypeAction
1031
     * @param guid
1032
     * @throws IOException
1033
     */
1034
    private void getNextRevision(String guid) throws IOException 
1035
    {
1036
        params.put("docid", new String[] { guid });
1037
        PrintWriter out = response.getWriter();
1038
        response.setStatus(200);
1039
        response.setContentType("text/xml");
1040
        //handler.handleGetRevisionAndDocTypeAction(out, params);
1041

    
1042
        try {
1043
            // Make sure there is a docid
1044
            if (guid == null || guid.equals("")) {
1045
                throw new Exception("User didn't specify docid!");
1046
            }
1047

    
1048
            // Look up the localId for this guid
1049
            IdentifierManager im = IdentifierManager.getInstance();
1050
            String localId = "";
1051
            try {
1052
                localId = im.getLocalId(guid);
1053
            } catch (McdbDocNotFoundException e) {
1054
                // TODO: Need to return the proper DataONE exception
1055
            }
1056
           
1057
            // Create a DBUtil object
1058
            DBUtil dbutil = new DBUtil();
1059
            // Get a rev and doctype
1060
            String revAndDocType = dbutil
1061
                    .getCurrentRevisionAndDocTypeForGivenDocument(localId);
1062
            int revision = Integer.parseInt(revAndDocType.split(";")[0]) + 1;
1063

    
1064
            out.println("<?xml version=\"1.0\"?>");
1065
            out.print("<next-revision>");
1066
            out.print(revision);
1067
            out.print("</next-revision>");
1068

    
1069
        } catch (Exception e) {
1070
            // Handle exception
1071
            response.setStatus(500);
1072
            out.println("<?xml version=\"1.0\"?>");
1073
            out.println("<error>");
1074
            out.println(e.getMessage());
1075
            out.println("</error>");
1076
        }
1077

    
1078
        out.close();
1079
    }
1080

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

    
1094
    /**
1095
     * Implements REST version of DataONE CRUD API --> get
1096
     * @param guid ID of data object to be read
1097
     */
1098
    private void getObject(String guid) {
1099
        CrudService cs = CrudService.getInstance();
1100
        cs.setParamsFromRequest(request);
1101
        AuthToken token = new AuthToken(sessionId);
1102
        OutputStream out = null;
1103
        try {
1104
            out = response.getOutputStream();
1105
            response.setStatus(200);
1106
            response.setContentType("text/xml");
1107
            if(guid != null)
1108
            { //get a specific document                
1109
                Identifier id = new Identifier();
1110
                id.setValue(guid);
1111
                try
1112
                {
1113
                    if(token == null)
1114
                    {
1115
                        token = new AuthToken("Public");
1116
                    }
1117
                    InputStream data = cs.get(token, id);
1118
                    IOUtils.copyLarge(data, response.getOutputStream());
1119
                }
1120
                catch(InvalidToken it)
1121
                {
1122
                    response.setStatus(500);
1123
                    serializeException(it, out); 
1124
                }
1125
                catch(ServiceFailure sf)
1126
                {
1127
                    response.setStatus(500);
1128
                    serializeException(sf, out); 
1129
                }
1130
                catch(NotAuthorized na)
1131
                {
1132
                    response.setStatus(500);
1133
                    serializeException(na, out); 
1134
                }
1135
                catch(NotFound nf)
1136
                {
1137
                    response.setStatus(500);
1138
                    serializeException(nf, out); 
1139
                }
1140
                catch(NotImplemented ni)
1141
                {
1142
                    response.setStatus(500);
1143
                    serializeException(ni, out); 
1144
                }
1145
                catch(Exception e)
1146
                {
1147
                    response.setStatus(500);
1148
                    System.out.println("Error with Crud.get().  " +
1149
                            "If this is an 'Exception producing data' error, " +
1150
                            "go to CrudService.get() for better debugging.  " +
1151
                            "Here's the error: " + e.getMessage());
1152
                    e.printStackTrace();
1153
                    ServiceFailure sf = new ServiceFailure("1030", 
1154
                            "IO Error in ResourceHandler.getObject: " + e.getMessage());
1155
                    serializeException(sf, out); 
1156
                }
1157
            }
1158
            else
1159
            { //call listObjects with specified params
1160
                Date startTime = null;
1161
                Date endTime = null;
1162
                ObjectFormat objectFormat = null;
1163
                boolean replicaStatus = false;
1164
                int start = 0;
1165
                //TODO: make the max count into a const
1166
                int count = 1000;
1167
                Enumeration paramlist = request.getParameterNames();
1168
                while (paramlist.hasMoreElements()) 
1169
                { //parse the params and make the crud call
1170
                    String name = (String) paramlist.nextElement();
1171
                    String[] value = (String[])request.getParameterValues(name);
1172
                    /*for(int i=0; i<value.length; i++)
1173
                    {
1174
                        System.out.println("name: " + name + " value: " + value[i]);
1175
                    }*/
1176
                    if(name.equals("startTime") && value != null)
1177
                    {
1178
                        try
1179
                        {
1180
                          //startTime = dateFormat.parse(value[0]);
1181
                            startTime = parseDateAndConvertToGMT(value[0]);
1182
                        }
1183
                        catch(Exception e)
1184
                        {  //if we can't parse it, just don't use the startTime param
1185
                            System.out.println("Could not parse startTime: " + value[0]);
1186
                            startTime = null;
1187
                        }
1188
                    }
1189
                    else if(name.equals("endTime") && value != null)
1190
                    {
1191
                        try
1192
                        {
1193
                          //endTime = dateFormat.parse(value[0]);
1194
                            endTime = parseDateAndConvertToGMT(value[0]);
1195
                        }
1196
                        catch(Exception e)
1197
                        {  //if we can't parse it, just don't use the endTime param
1198
                            System.out.println("Could not parse endTime: " + value[0]);
1199
                            endTime = null;
1200
                        }
1201
                    }
1202
                    else if(name.equals("objectFormat") && value != null)
1203
                    {
1204
                        objectFormat = ObjectFormat.convert(value[0]);
1205
                    }
1206
                    else if(name.equals("replicaStatus") && value != null)
1207
                    {
1208
                        if(value != null && 
1209
                           value.length > 0 && 
1210
                           (value[0].equals("true") || value[0].equals("TRUE") || value[0].equals("YES")))
1211
                        {
1212
                            replicaStatus = true;
1213
                        }
1214
                    }
1215
                    else if(name.equals("start") && value != null)
1216
                    {
1217
                        start = new Integer(value[0]).intValue();
1218
                    }
1219
                    else if(name.equals("count") && value != null)
1220
                    {
1221
                        count = new Integer(value[0]).intValue();
1222
                    }
1223
                }
1224
                //make the crud call
1225
                System.out.println("token: " + token + " startTime: " + startTime +
1226
                        " endtime: " + endTime + " objectFormat: " + 
1227
                        objectFormat + " replicaStatus: " + replicaStatus + 
1228
                        " start: " + start + " count: " + count);
1229
               
1230
                ObjectList ol = cs.listObjects(token, startTime, endTime, 
1231
                        objectFormat, replicaStatus, start, count);
1232
                
1233
                StringReader sr = new StringReader(ol.toString());                
1234
                out = response.getOutputStream();  
1235
                response.setStatus(200);
1236
                response.setContentType("text/xml");
1237
                // Serialize and write it to the output stream
1238
                
1239
                try {
1240
                    serializeServiceType(ObjectList.class, ol, out);
1241
                } catch (JiBXException e) {
1242
                    throw new ServiceFailure("1190", "Failed to serialize ObjectList: " + e.getMessage());
1243
                }
1244
            }
1245
        } catch (BaseException e) {
1246
                response.setStatus(500);
1247
                serializeException(e, out);
1248
        } catch (IOException e) {
1249
            e.printStackTrace();
1250
            response.setStatus(500);
1251
            ServiceFailure sf = new ServiceFailure("1030", 
1252
                    "IO Error in ResourceHandler.getObject: " + e.getMessage());
1253
            serializeException(sf, out); 
1254
        } catch(NumberFormatException ne) {
1255
            response.setStatus(500);
1256
            InvalidRequest ir = new InvalidRequest("1030", "Invalid format for parameter: " + ne.getMessage());
1257
            serializeException(ir, out);
1258
        } catch (Exception e) {
1259
            e.printStackTrace();
1260
            response.setStatus(500);
1261
            ServiceFailure sf = new ServiceFailure("1030", 
1262
                    "Exception " + e.getClass().getName() + " raised while handling listObjects request: " + 
1263
                    e.getMessage());
1264
            serializeException(sf, out);
1265
        }
1266
    }
1267
    
1268
    /**
1269
     * parse a date and return it in GMT if it ends with a 'Z'
1270
     * @param date
1271
     * @return
1272
     * @throws ParseException
1273
     */
1274
    private Date parseDateAndConvertToGMT(String date) throws ParseException
1275
    {
1276
        try
1277
        {   //the format we want
1278
            return dateFormat.parse(date);
1279
        }
1280
        catch(java.text.ParseException pe)
1281
        {   //try another legacy format
1282
            DateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'");
1283
            dateFormat2.setTimeZone(TimeZone.getTimeZone("GMT-0"));
1284
            return dateFormat2.parse(date);
1285
        }    
1286
    }
1287

    
1288
    /**
1289
     * Implements REST version of DataONE CRUD API --> getSystemMetadata
1290
     * @param guid ID of data object to be read
1291
     */
1292
    private void getSystemMetadataObject(String guid) {
1293
        CrudService cs = CrudService.getInstance();
1294
        cs.setParamsFromRequest(request);
1295
        AuthToken token = new AuthToken(sessionId);
1296
        OutputStream out = null;
1297
        try {
1298
            response.setContentType("text/xml");
1299
            response.setStatus(200);
1300
            out = response.getOutputStream();
1301
            Identifier id = new Identifier();
1302
            id.setValue(guid);
1303
            SystemMetadata sysmeta = cs.getSystemMetadata(token, id);
1304
            
1305
            // Serialize and write it to the output stream
1306
            try {
1307
                //TODO: look at the efficiency of this method.  The system metadata
1308
                //is read from metacat (in CrudService) as xml, then serialized
1309
                //to a SystemMetadat object, then returned here, then serizlized
1310
                //back to XML to be sent to the response.
1311
                serializeServiceType(SystemMetadata.class, sysmeta, out);
1312
            } catch (JiBXException e) {
1313
                throw new ServiceFailure("1190", "Failed to serialize SystemMetadata: " + e.getMessage());
1314
            }
1315
        } catch (BaseException e) {
1316
            response.setStatus(500);
1317
                serializeException(e, out);
1318
        } catch (IOException e) {
1319
            response.setStatus(500);
1320
            ServiceFailure sf = new ServiceFailure("1030", 
1321
                    "Error in ResourceHandler.getSystemMetadataObject: " + e.getMessage());
1322
            serializeException(sf, out);
1323
        } finally {
1324
            IOUtils.closeQuietly(out);
1325
        }
1326
    }
1327
    
1328
    /**
1329
     * serialize an object of type to out
1330
     * @param type the class of the object to serialize (i.e. SystemMetadata.class)
1331
     * @param object the object to serialize
1332
     * @param out the stream to serialize it to
1333
     * @throws JiBXException
1334
     */
1335
    private void serializeServiceType(Class type, Object object, OutputStream out)
1336
      throws JiBXException
1337
    {
1338
        IBindingFactory bfact = BindingDirectory.getFactory(type);
1339
        IMarshallingContext mctx = bfact.createMarshallingContext();
1340
        mctx.marshalDocument(object, "UTF-8", null, out);
1341
    }
1342
    
1343
    /**
1344
     * deserialize an object of type from is
1345
     * @param type the class of the object to serialize (i.e. SystemMetadata.class)
1346
     * @param is the stream to deserialize from
1347
     * @throws JiBXException
1348
     */
1349
    private Object deserializeServiceType(Class type, InputStream is)
1350
      throws JiBXException
1351
    {
1352
        IBindingFactory bfact = BindingDirectory.getFactory(type);
1353
        IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
1354
        Object o = (Object) uctx.unmarshalDocument(is, null);
1355
        return o;
1356
    }
1357
    
1358
    /**
1359
     * Earthgrid API > Query Service > Query Function : translates ecogrid query document to metacat query 
1360
     * then calls DBQuery > createResultDocument function and then again translate resultset to ecogrid resultset
1361
     * 
1362
     * NOTE:
1363
     *      This is the only method that uses EcoGrid classes for its implementation.  
1364
     *      It does so because it takes an EcoGrid Query as input, and outputs an
1365
     *      EcoGrid ResultSet document.  These documents are parsed by the auto-generated
1366
     *      EcoGrid classes from axis, and so we link to them here rather than re-inventing them.
1367
     *      This creates a circular dependency, because the Metacat classes are needed
1368
     *      to build the EcoGrid implementation, and the EcoGrid jars are needed to build this query()
1369
     *      method.  This circularity could be resolved by moving the EcoGrid classes
1370
     *      to Metacat directly.  As we transition away from EcoGrid SOAP methods in
1371
     *      favor of these REST interfaces, this circular dependency can be eliminated.
1372
     *        
1373
     * @throws Exception
1374
     */
1375
    private void query() throws Exception {
1376
        /*  This block commented out because of the EcoGrid circular dependency.
1377
         *  For now, query will not be supported until the circularity can be
1378
         *  resolved, probably by moving the ecogrid query syntax transformers
1379
         *  directly into the Metacat codebase.  MBJ 2010-02-03
1380
         
1381
        try {
1382
            EcogridQueryParser parser = new EcogridQueryParser(request
1383
                    .getReader());
1384
            parser.parseXML();
1385
            QueryType queryType = parser.getEcogridQuery();
1386
            EcogridJavaToMetacatJavaQueryTransformer queryTransformer = 
1387
                new EcogridJavaToMetacatJavaQueryTransformer();
1388
            QuerySpecification metacatQuery = queryTransformer
1389
                    .transform(queryType);
1390

    
1391
            DBQuery metacat = new DBQuery();
1392

    
1393
            boolean useXMLIndex = (new Boolean(PropertyService
1394
                    .getProperty("database.usexmlindex"))).booleanValue();
1395
            String xmlquery = "query"; // we don't care the query in resultset,
1396
            // the query can be anything
1397
            PrintWriter out = null; // we don't want metacat result, so set out null
1398

    
1399
            // parameter: queryspecification, user, group, usingIndexOrNot
1400
            StringBuffer result = metacat.createResultDocument(xmlquery,
1401
                    metacatQuery, out, username, groupNames, useXMLIndex);
1402

    
1403
            // create result set transfer       
1404
            String saxparser = PropertyService.getProperty("xml.saxparser");
1405
            MetacatResultsetParser metacatResultsetParser = new MetacatResultsetParser(
1406
                    new StringReader(result.toString()), saxparser, queryType
1407
                            .getNamespace().get_value());
1408
            ResultsetType records = metacatResultsetParser.getEcogridResult();
1409

    
1410
            System.out
1411
                    .println(EcogridResultsetTransformer.toXMLString(records));
1412
            response.setContentType("text/xml");
1413
            out = response.getWriter();
1414
            out.print(EcogridResultsetTransformer.toXMLString(records));
1415

    
1416
        } catch (Exception e) {
1417
            e.printStackTrace();
1418
        }*/
1419
        response.setContentType("text/xml");
1420
        response.setStatus(501);
1421
        PrintWriter out = response.getWriter();
1422
        out.print("<error>Query operation not yet supported by Metacat.</error>");
1423
        out.close();
1424
    }
1425
    
1426
    private String streamToString(InputStream is)
1427
    throws IOException
1428
    {
1429
        return IOUtil.toString(is);
1430
    }
1431

    
1432
    private InputStream stringToStream(String s)
1433
    throws IOException
1434
    {
1435
        ByteArrayInputStream bais = new ByteArrayInputStream(s.getBytes(MetaCatServlet.DEFAULT_ENCODING));
1436
        return bais;
1437
    }
1438
    
1439
    /**
1440
     * locate the boundary marker for an MMP
1441
     * @param is
1442
     * @return
1443
     * @throws IOException
1444
     */
1445
    protected static String[] findBoundaryString(InputStream is)
1446
        throws IOException
1447
    {
1448
        String[] endResult = new String[2];
1449
        String boundary = "";
1450
        String searchString = "boundary=";
1451
        boolean doneWithCurrentArray = false;
1452
        byte[] b = new byte[1024];
1453
        int numbytes = is.read(b, 0, 1024);
1454

    
1455
        while(numbytes != -1)
1456
        {
1457
            String s = new String(b, 0, numbytes);
1458
            int searchStringIndex = s.indexOf(searchString);
1459
            
1460
            if(s.indexOf("\"", searchStringIndex + searchString.length() + 1) == -1)
1461
            { //the end of the boundary is in the next byte array
1462
                boundary = s.substring(searchStringIndex + searchString.length() + 1, s.length());
1463
            }
1464
            else if(!boundary.startsWith("--"))
1465
            { //we can read the whole boundary from this byte array
1466
                boundary = s.substring(searchStringIndex + searchString.length() + 1, 
1467
                    s.indexOf("\"", searchStringIndex + searchString.length() + 1));
1468
                boundary = "--" + boundary;
1469
                endResult[0] = boundary;
1470
                endResult[1] = s.substring(s.indexOf("\"", searchStringIndex + searchString.length() + 1) + 1,
1471
                        s.length());
1472
                break;
1473
            }
1474
            else
1475
            { //we're now reading the 2nd byte array to get the rest of the boundary
1476
                searchString = "\"";
1477
                searchStringIndex = s.indexOf(searchString);
1478
                boundary += s.substring(0, searchStringIndex);
1479
                boundary = "--" + boundary;
1480
                endResult[0] = boundary;
1481
                endResult[1] = s.substring(s.indexOf("\"", searchStringIndex + searchString.length() + 1) + 1,
1482
                        s.length());
1483
                break;
1484
            }
1485
        }
1486
        System.out.println("boundary is: '" + boundary + "'");
1487
        return endResult;
1488
    }
1489
    
1490
    /**
1491
     * find the part marked by the boundary and the searchstring and write it to f
1492
     * @param beginSearch
1493
     * @param is
1494
     * @param boundary
1495
     * @param searchString
1496
     * @param f
1497
     * @return
1498
     * @throws IOException
1499
     */
1500
    protected String writeMMPPartToFile(String beginSearch, 
1501
            InputStream is, String boundary, String searchString, File f)
1502
        throws IOException
1503
    {
1504
        Logger logMetacat = Logger.getLogger(ResourceHandler.class);
1505
        logMetacat.info("writing MMP parts");
1506
        //String s = beginSearch;
1507
        String s = null;
1508
        FileOutputStream fos = new FileOutputStream(f);
1509
        int numread = 0;
1510
        byte[] b = new byte[1024];
1511
        String writeString = "";
1512
        
1513
        if(s == null)
1514
        {   //starting with the first part of the stream 
1515
            numread = is.read(b, 0, 1024);
1516
            s = new String(b, 0, numread);
1517
        }
1518
        
1519
        if(beginSearch != null)
1520
        {
1521
            s = beginSearch + s;
1522
        }
1523
        
1524
        boolean useCurrentS = true;
1525
        boolean searchForBoundary = false;
1526
        String seekString = searchString;
1527
        
1528
        while(numread != -1)
1529
        {
1530
            logMetacat.info("////////////////////////iterating");
1531
            logMetacat.info("searchForBoundary: " + searchForBoundary);
1532
            logMetacat.info("useCurrentS: " + useCurrentS);
1533
            logMetacat.info("seekString: " + seekString);
1534
            logMetacat.info("in string: " + s);
1535
            if(searchForBoundary)
1536
            {
1537
                seekString = boundary;
1538
            }
1539
            else
1540
            {
1541
                seekString = searchString;
1542
            }
1543
            
1544
            int[] result = StreamUtil.lookForMatch(seekString, s);
1545
            if(!useCurrentS)
1546
            {
1547
                numread = is.read(b, 0, 1024);
1548
                if(numread != -1)
1549
                {
1550
                    s = new String(b, 0, numread);
1551
                }
1552
                else
1553
                {
1554
                    break;
1555
                }
1556
            }
1557
            
1558
            logMetacat.info("2seekString: " + seekString);
1559
            logMetacat.info("2in string: " + s);
1560
            
1561
            if(result[0] >= 0 && result[1] == seekString.length())
1562
            {
1563
                //searchString is full in s
1564
                logMetacat.info("seekstring is fully in s");
1565
                if(!searchForBoundary)
1566
                {   //we're looking for searchString and we found it
1567
                    //chop off the searchString itself and start writing
1568
                    //until we find boundary
1569
                    s = s.substring(result[0] + result[1], s.length());
1570
                    if(s.length() > 0)
1571
                    {
1572
                        useCurrentS = true;
1573
                    }
1574
                    else
1575
                    {
1576
                        useCurrentS = false;
1577
                    }
1578
                    searchForBoundary = true;
1579
                }
1580
                else
1581
                {   //we're writing, but we found the boundary in this chunk
1582
                    
1583
                    writeString = s.substring(0, result[0]);
1584
                    //System.out.println("writing1: " + writeString);
1585
                    fos.write(writeString.getBytes(MetaCatServlet.DEFAULT_ENCODING));
1586
                    //we're done.  break and return;
1587
                    return s.substring(result[0] + result[1], s.length());
1588
                }
1589
            }
1590
            else if(result[0] > 0 && result[1] != seekString.length())
1591
            {
1592
                logMetacat.info("seekstring is partially in s");
1593
                //seekString is partially in s
1594
                //more specifically, the beginning of seekString is at the end
1595
                //of s
1596
                
1597
                //get the next chunk right now, see if the beginning matches
1598
                numread = is.read(b, 0, 1024);
1599
                String s2 = new String(b, 0, numread);
1600
                s += s2;
1601
                useCurrentS = true;
1602
            }
1603
            else
1604
            {
1605
                logMetacat.info("seekstring is not in s");
1606
                //searchString is not in s 
1607
                if(searchForBoundary)
1608
                {
1609
                    //System.out.println("writing2: " + s);
1610
                    fos.write(s.getBytes(MetaCatServlet.DEFAULT_ENCODING));
1611
                }
1612
                numread = is.read(b, 0, 1024);
1613
                if(numread != -1)
1614
                {
1615
                    s = new String(b, 0, numread);
1616
                }
1617
                else
1618
                {
1619
                    break;
1620
                }
1621
                useCurrentS = true;
1622
            }
1623
        }
1624
        return "";
1625
    }
1626
    
1627
    /**
1628
     * write mime multipart parts to files.  this defaults ot getting 
1629
     * the parts "systemmetadata" and "object"
1630
     * @param is
1631
     * @return
1632
     * @throws IOException
1633
     */
1634
    protected Hashtable<String, File> writeMMPPartsToFiles(InputStream is)
1635
        throws IOException
1636
    {
1637
        String[] searchStrings = {
1638
                "Content-Disposition: attachment; filename=systemmetadata\n\n",
1639
                "Content-Disposition: attachment; filename=object\n\n"};
1640
        String[] names = {
1641
                "systemmetadata",
1642
                "object"
1643
        };
1644
        return writeMMPPartsToFiles(is, searchStrings, names);
1645
    }
1646
    
1647
    /**
1648
     * write the mime multipart parts to files.  search for the parts by the names
1649
     * of the searchStrings in order
1650
     * @param is the inputstream of the MMP
1651
     * @param searchStrings the string to search for for the part in the MMP
1652
     * @param names the name to give the indexed part in the returned hashtable
1653
     * @return
1654
     * @throws IOException
1655
     */
1656
    protected Hashtable<String, File> writeMMPPartsToFiles(InputStream is, 
1657
            String[] searchStrings, String[] names)
1658
        throws IOException
1659
    {
1660
        Logger logMetacat = Logger.getLogger(ResourceHandler.class);
1661
        logMetacat.info("Processing Mime Multipart");
1662
        //String isStr = IOUtils.toString(is);
1663
        //System.out.println("isStr: " + isStr);
1664
        //is = IOUtils.toInputStream(isStr);
1665
        String[] boundaryResults = findBoundaryString(is);
1666
        String boundary = boundaryResults[0];
1667
        String s = boundaryResults[1];
1668
        
1669
        
1670
        File[] fileArr = getMMPTempFiles(searchStrings, names);
1671
        Hashtable<String, File> h = new Hashtable<String, File>();
1672
        for(int i=0; i<searchStrings.length; i++)
1673
        {
1674
            System.out.println("searchStrings: " + searchStrings[i]);
1675
            System.out.println("file: " + fileArr[0].getAbsolutePath());
1676
            logMetacat.info("writing mime part " + searchStrings[i] + " to " + fileArr[0].getAbsolutePath());
1677
            System.out.println("s: " + s);
1678
            System.out.println("is: " + is);
1679
            
1680
            s = writeMMPPartToFile(s.trim(), is, boundary, searchStrings[i], fileArr[i]);
1681
            logMetacat.info("writeMMPPartToFile returned '" + s.trim() + "' after processing part " + searchStrings[i]);
1682
            h.put(names[i], fileArr[i]);
1683
        }
1684
        
1685
        return h;
1686
    }
1687
    
1688
    private static File[] getMMPTempFiles(String[] searchStrings, String[] names)
1689
        throws IOException
1690
    {
1691
        Logger logMetacat = Logger.getLogger(ResourceHandler.class);
1692
        File tmpDir;
1693
        try
1694
        {
1695
            tmpDir = new File(PropertyService.getProperty("application.tempDir"));
1696
        }
1697
        catch(PropertyNotFoundException pnfe)
1698
        {
1699
            logMetacat.error("ResourceHandler.writeMMPPartstoFiles: " +
1700
                    "application.tmpDir not found.  Using /tmp instead.");
1701
            tmpDir = new File("/tmp");
1702
        }
1703
        long datetimetag = new Date().getTime();
1704
        File[] fileArr = new File[searchStrings.length];
1705
        for(int i=0; i<searchStrings.length; i++)
1706
        {
1707
            File f = new File(tmpDir, names[i] + "." + datetimetag + ".tmp");
1708
            fileArr[i] = f;
1709
        }
1710
        
1711
        return fileArr;
1712
    }
1713
    
1714
    /**
1715
     * return a vector where the first element is a string that represents the system
1716
     * metadata and the 2nd element is an InputStream that is the object
1717
     */
1718
    protected Hashtable<String, File> processMMP(final InputStream is)
1719
      throws IOException
1720
    {
1721
        return writeMMPPartsToFiles(is);
1722
    }
1723
    
1724
    /**
1725
     * Earthgrid API > Put Service >Put Function : calls MetacatHandler > handleInsertOrUpdateAction 
1726
     * 
1727
     * @param guid ID of data object to be inserted or updated
1728
     * @throws IOException
1729
     */
1730
    private void putObject(String guid, String action) {
1731
        logMetacat.debug("Entering putObject: " + guid + "/" + action);
1732
        OutputStream out = null;
1733
        Hashtable<String, File> parts = null;
1734
        try {
1735
            out = response.getOutputStream();
1736
            response.setStatus(200);
1737
            response.setContentType("text/xml");
1738
        } catch (IOException e1) {
1739
            logMetacat.error("Could not get the output stream for writing in putObject");
1740
        }
1741
        try {
1742
            
1743
            // Read the incoming data from its Mime Multipart encoding
1744
            logMetacat.debug("Disassembling MIME multipart form");
1745
            InputStream object = null;
1746
            InputStream sysmeta = null;
1747
            
1748
            try
1749
            {
1750
                //String req = IOUtils.toString(request.getInputStream());
1751
                //System.out.println("request: " + req);
1752
                //InputStream reqStr = IOUtils.toInputStream(req);
1753
                InputStream reqStr = request.getInputStream();
1754
                parts = processMMP(reqStr);
1755
                object = new FileInputStream(parts.get("object"));
1756
                sysmeta = new FileInputStream(parts.get("systemmetadata"));
1757
                
1758
                /*String obj = IOUtils.toString(object);
1759
                String sm = IOUtils.toString(sysmeta);
1760
                System.out.println("object: " + obj);
1761
                System.out.println("sm: " + sm);
1762
                object = IOUtils.toInputStream(obj);
1763
                sysmeta = IOUtils.toInputStream(sm);*/
1764
                
1765
            }
1766
            catch(IOException ioe)
1767
            {
1768
                throw new ServiceFailure("1202", 
1769
                        "IOException when processing Mime Multipart: " + ioe.getMessage());
1770
            }
1771
            
1772
            if ( action.equals(FUNCTION_NAME_INSERT)) { //handle inserts
1773

    
1774
                // Check if the objectId exists
1775
                IdentifierManager im = IdentifierManager.getInstance();
1776
                if (im.identifierExists(guid)) {
1777
                    throw new IdentifierNotUnique("1000", "Identifier is already in use: " + guid);
1778
                }
1779

    
1780
                logMetacat.debug("Commence creation...");
1781
                IBindingFactory bfact =
1782
                    BindingDirectory.getFactory(SystemMetadata.class);
1783
                IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
1784
                SystemMetadata m = (SystemMetadata) uctx.unmarshalDocument(sysmeta, null);
1785

    
1786
                CrudService cs = CrudService.getInstance();
1787
                AuthToken token = new AuthToken(sessionId); 
1788
                cs.setParamsFromRequest(request);
1789
                Identifier id = new Identifier();
1790
                id.setValue(guid);
1791
                System.out.println("creating object with guid " + id.getValue());
1792
                Identifier rId = cs.create(token, id, object, m);
1793
                serializeServiceType(Identifier.class, rId, out);
1794
                
1795
            } else if (action.equals(FUNCTION_NAME_UPDATE)) { //handle updates
1796
                IdentifierManager im = IdentifierManager.getInstance();
1797
                CrudService cs = CrudService.getInstance();
1798
                Identifier obsoletedGuid = new Identifier();
1799
                Identifier id = new Identifier();
1800
                id.setValue(guid);
1801
                AuthToken token = new AuthToken(sessionId);
1802
                
1803
                //do some checks
1804
                if(params.get("obsoletedGuid") == null)
1805
                {
1806
                    throw new InvalidRequest("1202", "obsoletedGuid must be contained in the request parameters.");
1807
                }
1808
                //get the obsoletedGuid
1809
                String[] obsGuidS = params.get("obsoletedGuid");
1810
                obsoletedGuid.setValue(obsGuidS[0]);
1811
                
1812
                if (!im.identifierExists(obsoletedGuid.getValue())) 
1813
                {
1814
                    throw new InvalidRequest("1202", "The guid you are trying to update does not exist.");
1815
                }
1816
                
1817
                
1818
                logMetacat.debug("Commence update...");
1819
                
1820
                //get the systemmetadata
1821
                IBindingFactory bfact =
1822
                        BindingDirectory.getFactory(SystemMetadata.class);
1823
                    IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
1824
                    SystemMetadata m = (SystemMetadata) uctx.unmarshalDocument(sysmeta, null);
1825
                
1826
                //do the update
1827
                try
1828
                {
1829
                    cs.setParamsFromRequest(request);
1830
                    Identifier rId = cs.update(token, id, object, obsoletedGuid, m);
1831
                    serializeServiceType(Identifier.class, rId, out);
1832
                }
1833
                catch(NotFound e)
1834
                {
1835
                    throw new InvalidRequest("1202", "The guid you are trying to update does not exist.");
1836
                }
1837
                
1838
            } else {
1839
                throw new InvalidRequest("1000", "Operation must be create or update.");
1840
            }
1841
            
1842
            //clean up the MMP files
1843
            parts.get("systemmetadata").delete();
1844
            parts.get("object").delete();
1845
        } catch (NotAuthorized e) {
1846
            response.setStatus(500);
1847
            serializeException(e, out);
1848
        } catch (InvalidToken e) {
1849
            response.setStatus(500);
1850
            serializeException(e, out);
1851
        } catch (ServiceFailure e) {
1852
            response.setStatus(500);
1853
            serializeException(e, out);
1854
        } catch (IdentifierNotUnique e) {
1855
            response.setStatus(500);
1856
            serializeException(e, out);
1857
        } catch (UnsupportedType e) {
1858
            response.setStatus(500);
1859
            serializeException(e, out);
1860
        } catch (InsufficientResources e) {
1861
            response.setStatus(500);
1862
            serializeException(e, out);
1863
        } catch (InvalidSystemMetadata e) {
1864
            response.setStatus(500);
1865
            serializeException(e, out);
1866
        } catch (NotImplemented e) {
1867
            response.setStatus(500);
1868
            serializeException(e, out);
1869
        } catch (InvalidRequest e) {
1870
            response.setStatus(500);
1871
            serializeException(e, out);
1872
        } /*catch (MessagingException e) {
1873
            ServiceFailure sf = new ServiceFailure("1000", e.getMessage());
1874
            serializeException(sf, out);
1875
        } catch (IOException e) {
1876
            response.setStatus(500);
1877
            ServiceFailure sf = new ServiceFailure("1000", e.getMessage());
1878
            serializeException(sf, out);
1879
        }*/ catch (JiBXException e) {
1880
            response.setStatus(500);
1881
            e.printStackTrace(System.out);
1882
            InvalidSystemMetadata ism = new InvalidSystemMetadata("1080", e.getMessage());
1883
            serializeException(ism, out);
1884
        }
1885
        finally
1886
        {
1887
            if(parts != null)
1888
            {
1889
                Enumeration keys = parts.keys();
1890
                while(keys.hasMoreElements())
1891
                {
1892
                    String key = (String)keys.nextElement();
1893
                    File f = parts.get(key);
1894
                    f.delete();
1895
                }
1896
            }
1897
        }
1898
    }
1899

    
1900
    /**
1901
     * Handle delete 
1902
     * @param guid ID of data object to be deleted
1903
     * @throws IOException
1904
     */
1905
    private void deleteObject(String guid) throws IOException 
1906
    {
1907
        // Look up the localId for this global identifier
1908
        System.out.println("!!!!!!!!!!!!!!!!!deleting object " + guid);
1909
        IdentifierManager im = IdentifierManager.getInstance();
1910
        String localId = "";
1911
        OutputStream out = response.getOutputStream();
1912
        response.setStatus(200);
1913
        try {
1914
            localId = im.getLocalId(guid);
1915
        } catch (McdbDocNotFoundException e) {
1916
            NotFound nf = new NotFound("1340", "Document with guid " + guid + " not found.");
1917
            response.setStatus(404);
1918
            serializeException(nf, out);
1919
        }
1920
       
1921
        AuthToken token = new AuthToken(sessionId);
1922
        CrudService cs = CrudService.getInstance();
1923
        Identifier id = new Identifier();
1924
        id.setValue(guid);
1925
        try
1926
        {
1927
            System.out.println("Calling delete");
1928
            cs.delete(token, id);
1929
            serializeServiceType(Identifier.class, id, out);
1930
        } 
1931
        catch (NotAuthorized e) {
1932
            response.setStatus(500);
1933
            serializeException(e, out);
1934
        } catch (InvalidToken e) {
1935
            response.setStatus(500);
1936
            serializeException(e, out);
1937
        } catch (ServiceFailure e) {
1938
            response.setStatus(500);
1939
            serializeException(e, out);
1940
        } catch (NotImplemented e) {
1941
            response.setStatus(500);
1942
            serializeException(e, out);
1943
        } catch (InvalidRequest e) {
1944
            response.setStatus(500);
1945
            serializeException(e, out);
1946
        } catch(NotFound e) {
1947
            response.setStatus(500);
1948
            serializeException(e, out);
1949
        } catch(JiBXException e) {
1950
            response.setStatus(500);
1951
            serializeException(new ServiceFailure("1350", "JiBXException: " + e.getMessage()), out);
1952
        }
1953
        out.close();
1954
    }
1955
    
1956
    /**
1957
     * set the access perms on a document
1958
     * @throws IOException
1959
     */
1960
    private void setaccess() throws Exception
1961
    {
1962
        try
1963
        {
1964
            String guid = params.get("guid")[0];
1965
            Identifier id = new Identifier();
1966
            id.setValue(guid);
1967
            AuthToken token = new AuthToken(sessionId);
1968
            String principal = params.get("principal")[0];
1969
            String permission = params.get("permission")[0];
1970
            String permissionType = params.get("permissionType")[0];
1971
            String permissionOrder = params.get("permissionOrder")[0];
1972
            String setSystemMetadata = params.get("setsystemmetadata")[0];
1973
            boolean ssm = false;
1974
            if(setSystemMetadata.equals("true") || setSystemMetadata.equals("TRUE") ||
1975
                    setSystemMetadata.equals("yes"))
1976
            {
1977
                ssm = true;
1978
            }
1979
            CrudService cs = CrudService.getInstance();
1980
            //TODO: remove the setsystemmetadata param and set this so the systemmetadata always gets set
1981
            cs.setAccess(token, id, principal, permission, permissionType, permissionOrder, ssm);
1982
        }
1983
        catch(Exception e)
1984
        {
1985
            response.setStatus(500);
1986
            printError("Error setting access in ResourceHandler: " + e.getMessage(), response);
1987
            throw e;
1988
        }
1989
    }
1990

    
1991
    /**
1992
     * Earthgrid API > Authentication Service > Login Function : calls MetacatHandler > handleLoginAction
1993
     * 
1994
     * @throws IOException
1995
     */
1996
    private void login() throws IOException {
1997
        PrintWriter out = response.getWriter();
1998
        response.setStatus(200);
1999
        response.setContentType("text/xml");
2000
        handler.handleLoginAction(out, params, request, response);
2001
        out.close();
2002
    }
2003

    
2004
    /**
2005
     * Earthgrid API > Authentication Service > Logout Function : calls MetacatHandler > handleLogoutAction
2006
     * 
2007
     * @throws IOException
2008
     */
2009
    private void logout() throws IOException {
2010
        PrintWriter out = response.getWriter();
2011
        response.setStatus(200);
2012
        response.setContentType("text/xml");
2013
        handler.handleLogoutAction(out, params, request, response);
2014
        out.close();
2015
    }
2016

    
2017
    /**
2018
     * Prints xml response
2019
     * @param message Message to be displayed
2020
     * @param response Servlet response that xml message will be printed 
2021
     * */
2022
    private void printError(String message, HttpServletResponse response) {
2023
        try {
2024
            logMetacat.error("ResourceHandler: Printing error to servlet response: " + message);
2025
            PrintWriter out = response.getWriter();
2026
            response.setContentType("text/xml");
2027
            out.println("<?xml version=\"1.0\"?>");
2028
            out.println("<error>");
2029
            out.println(message);
2030
            out.println("</error>");
2031
            out.close();
2032
        } catch (IOException e) {
2033
            e.printStackTrace();
2034
        }
2035
    }
2036
    
2037
    /**
2038
     * serialize a D1 exception using jibx
2039
     * @param e
2040
     * @param out
2041
     */
2042
    private void serializeException(BaseException e, OutputStream out) {
2043
        // TODO: Use content negotiation to determine which return format to use
2044
        response.setContentType("text/xml");
2045
        response.setStatus(e.getCode());
2046
        
2047
        logMetacat.error("ResourceHandler: Serializing exception with code " + e.getCode() + ": " + e.getMessage());
2048
        e.printStackTrace();
2049
        
2050
        try {
2051
            IOUtils.write(e.serialize(BaseException.FMT_XML), out);
2052
        } catch (IOException e1) {
2053
            logMetacat.error("Error writing exception to stream. " 
2054
                    + e1.getMessage());
2055
        }
2056
    }
2057
    
2058
    /**
2059
     * create a new ServiceMethod declaration
2060
     * @param name
2061
     * @param rest
2062
     * @param implemented
2063
     * @return
2064
     */
2065
    private ServiceMethod getServiceMethod(String name, String rest, boolean implemented)
2066
    {
2067
        ServiceMethod sm = new ServiceMethod();
2068
        sm.setImplemented(implemented);
2069
        sm.setName(name);
2070
        sm.setRest(rest);
2071
        return sm;
2072
    }
2073

    
2074
}
(4-4/5)