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.client.MNode;
46
import org.dataone.mimemultipart.MultipartRequest;
47
import org.dataone.mimemultipart.MultipartRequestResolver;
48
import org.dataone.service.NodeListParser;
49
import org.dataone.service.exceptions.BaseException;
50
import org.dataone.service.exceptions.IdentifierNotUnique;
51
import org.dataone.service.exceptions.InsufficientResources;
52
import org.dataone.service.exceptions.InvalidRequest;
53
import org.dataone.service.exceptions.InvalidSystemMetadata;
54
import org.dataone.service.exceptions.InvalidToken;
55
import org.dataone.service.exceptions.NotAuthorized;
56
import org.dataone.service.exceptions.NotImplemented;
57
import org.dataone.service.exceptions.ServiceFailure;
58
import org.dataone.service.exceptions.UnsupportedType;
59
import org.dataone.service.exceptions.NotFound;
60
import org.dataone.service.types.*;
61
import org.jibx.runtime.BindingDirectory;
62
import org.jibx.runtime.IBindingFactory;
63
import org.jibx.runtime.IMarshallingContext;
64
import org.jibx.runtime.IUnmarshallingContext;
65
import org.jibx.runtime.JiBXException;
66

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

    
81
import org.dataone.service.streaming.util.StreamUtil;
82

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

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

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

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

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

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

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

    
251
    private Hashtable<String, String[]> params;
252

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

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

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

    
292
                params = new Hashtable<String, String[]>();
293
                initParams();
294

    
295
                Timer timer = new Timer();
296
                handler = new MetacatHandler(timer);
297

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

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

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

    
361
                    logMetacat.debug("verb:" + httpVerb);
362

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

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

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

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

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

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

    
944
        String name = null;
945
        String[] value = null;
946
        Enumeration paramlist = request.getParameterNames();
947
        while (paramlist.hasMoreElements()) {
948
            name = (String) paramlist.nextElement();
949
            value = request.getParameterValues(name);
950
            params.put(name, value);
951
        }
952
    }
953

    
954
    /**
955
     * 
956
     * Load user details of metacat session from the request 
957
     * 
958
     */
959
    private void loadSessionData()
960
      throws Exception
961
    {
962
        SessionData sessionData = RequestUtil.getSessionData(request);
963
        try
964
        {
965
            username = null;
966
            password = null;
967
            groupNames = null;
968
            sessionId = null;
969
            
970
            boolean validSession = false;
971
            SessionService ss = SessionService.getInstance();
972
            System.out.println("sessionData: " + sessionData);
973
            if(sessionData == null)
974
            {
975
                username = "public";
976
                sessionId = "0";
977
                System.out.println("sessiondata is null.  Creating a public session.");
978
                return;
979
            }
980
            
981
            System.out.println("username: " + sessionData.getUserName());
982
            System.out.println("sessionid: " + sessionData.getId());
983
            //validate the session
984
            if(ss.isSessionRegistered(sessionData.getId()) && 
985
               !(sessionData.getUserName().equals("public") || sessionData.getId().equals("0")))
986
            {
987
                validSession = true;
988
            }
989
            
990
            if(validSession)
991
            {
992
                //if the session is valid, set these variables
993
                username = sessionData.getUserName();
994
                password = sessionData.getPassword();
995
                groupNames = sessionData.getGroupNames();
996
                sessionId = sessionData.getId();
997
                System.out.println("setting sessionid to " + sessionId);
998
                System.out.println("username: " + username);
999
            }
1000
            
1001
            //if the session is not valid or the username is null, set
1002
            //username to public
1003
            if (username == null) 
1004
            {
1005
                System.out.println("setting username to public.");
1006
                username = "public";
1007
            }
1008
        }
1009
        catch(Exception e)
1010
        {
1011
            e.printStackTrace();
1012
            throw new Exception("Could not load the session data: " + e.getMessage());
1013
        }
1014
    }
1015
    
1016
    /**
1017
     * generate missing system metadata for any science metadata objects
1018
     * that don't already have it. https://trac.dataone.org/ticket/591
1019
     * 
1020
     * called with POST meta/?op=generatemissingsystemmetadata
1021
     */
1022
    private void generateMissingSystemMetadata()
1023
    {
1024
        AuthToken token = new AuthToken(sessionId);
1025
        CrudService.getInstance().generateMissingSystemMetadata(token);
1026
    }
1027

    
1028
    /**
1029
     *  Earthgrid API > Identifier Service > isRegistered Function : 
1030
     *  calls MetacatHandler > handleIdIsRegisteredAction
1031
     * @param guid
1032
     * @throws IOException
1033
     */
1034
    private void isRegistered(String guid) throws IOException
1035
    {
1036
        
1037
        // Look up the localId for this guid
1038
        IdentifierManager im = IdentifierManager.getInstance();
1039
        String localId = "";
1040
        try {
1041
            localId = im.getLocalId(guid);
1042
        } catch (McdbDocNotFoundException e) {
1043
            // TODO: Need to return the proper DataONE exception
1044
        }
1045
        
1046
        params.put("docid", new String[] { localId });
1047
        PrintWriter out = response.getWriter();
1048
        response.setStatus(200);
1049
        response.setContentType("text/xml");
1050
        handler.handleIdIsRegisteredAction(out, params, response);
1051
        out.close();
1052
    }
1053

    
1054
    /**
1055
     * Earthgrid API > Identifier Service > getAllDocIds Function : 
1056
     * calls MetacatHandler > handleGetAllDocidsAction
1057
     * @throws IOException
1058
     */
1059
    private void getAllDocIds() throws IOException {
1060
        PrintWriter out = response.getWriter();
1061
        response.setStatus(200);
1062
        response.setContentType("text/xml");
1063
        handler.handleGetAllDocidsAction(out, params, response);
1064
        out.close();
1065
    }
1066

    
1067
    /**
1068
     * Earthgrid API > Identifier Service > getNextRevision Function : 
1069
     * calls MetacatHandler > handleGetRevisionAndDocTypeAction
1070
     * @param guid
1071
     * @throws IOException
1072
     */
1073
    private void getNextRevision(String guid) throws IOException 
1074
    {
1075
        params.put("docid", new String[] { guid });
1076
        PrintWriter out = response.getWriter();
1077
        response.setStatus(200);
1078
        response.setContentType("text/xml");
1079
        //handler.handleGetRevisionAndDocTypeAction(out, params);
1080

    
1081
        try {
1082
            // Make sure there is a docid
1083
            if (guid == null || guid.equals("")) {
1084
                throw new Exception("User didn't specify docid!");
1085
            }
1086

    
1087
            // Look up the localId for this guid
1088
            IdentifierManager im = IdentifierManager.getInstance();
1089
            String localId = "";
1090
            try {
1091
                localId = im.getLocalId(guid);
1092
            } catch (McdbDocNotFoundException e) {
1093
                // TODO: Need to return the proper DataONE exception
1094
            }
1095
           
1096
            // Create a DBUtil object
1097
            DBUtil dbutil = new DBUtil();
1098
            // Get a rev and doctype
1099
            String revAndDocType = dbutil
1100
                    .getCurrentRevisionAndDocTypeForGivenDocument(localId);
1101
            int revision = Integer.parseInt(revAndDocType.split(";")[0]) + 1;
1102

    
1103
            out.println("<?xml version=\"1.0\"?>");
1104
            out.print("<next-revision>");
1105
            out.print(revision);
1106
            out.print("</next-revision>");
1107

    
1108
        } catch (Exception e) {
1109
            // Handle exception
1110
            response.setStatus(500);
1111
            out.println("<?xml version=\"1.0\"?>");
1112
            out.println("<error>");
1113
            out.println(e.getMessage());
1114
            out.println("</error>");
1115
        }
1116

    
1117
        out.close();
1118
    }
1119

    
1120
    /**
1121
     * Earthgrid API > Identifier Service > getNextObject Function : 
1122
     * calls MetacatHandler > handleGetMaxDocidAction
1123
     * @throws IOException
1124
     */
1125
    private void getNextObject() throws IOException {
1126
        PrintWriter out = response.getWriter();
1127
        response.setStatus(200);
1128
        response.setContentType("text/xml");
1129
        handler.handleGetMaxDocidAction(out, params, response);
1130
        out.close();
1131
    }
1132

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

    
1327
    /**
1328
     * Implements REST version of DataONE CRUD API --> getSystemMetadata
1329
     * @param guid ID of data object to be read
1330
     */
1331
    private void getSystemMetadataObject(String guid) {
1332
        CrudService cs = CrudService.getInstance();
1333
        cs.setParamsFromRequest(request);
1334
        AuthToken token = new AuthToken(sessionId);
1335
        OutputStream out = null;
1336
        try {
1337
            response.setContentType("text/xml");
1338
            response.setStatus(200);
1339
            out = response.getOutputStream();
1340
            Identifier id = new Identifier();
1341
            id.setValue(guid);
1342
            SystemMetadata sysmeta = cs.getSystemMetadata(token, id);
1343
            
1344
            // Serialize and write it to the output stream
1345
            try {
1346
                //TODO: look at the efficiency of this method.  The system metadata
1347
                //is read from metacat (in CrudService) as xml, then serialized
1348
                //to a SystemMetadat object, then returned here, then serizlized
1349
                //back to XML to be sent to the response.
1350
                serializeServiceType(SystemMetadata.class, sysmeta, out);
1351
            } catch (JiBXException e) {
1352
                throw new ServiceFailure("1190", "Failed to serialize SystemMetadata: " + e.getMessage());
1353
            }
1354
        } catch (BaseException e) {
1355
            response.setStatus(500);
1356
                serializeException(e, out);
1357
        } catch (IOException e) {
1358
            response.setStatus(500);
1359
            ServiceFailure sf = new ServiceFailure("1030", 
1360
                    "Error in ResourceHandler.getSystemMetadataObject: " + e.getMessage());
1361
            serializeException(sf, out);
1362
        } finally {
1363
            IOUtils.closeQuietly(out);
1364
        }
1365
    }
1366
    
1367
    /**
1368
     * serialize an object of type to out
1369
     * @param type the class of the object to serialize (i.e. SystemMetadata.class)
1370
     * @param object the object to serialize
1371
     * @param out the stream to serialize it to
1372
     * @throws JiBXException
1373
     */
1374
    private void serializeServiceType(Class type, Object object, OutputStream out)
1375
      throws JiBXException
1376
    {
1377
        IBindingFactory bfact = BindingDirectory.getFactory(type);
1378
        IMarshallingContext mctx = bfact.createMarshallingContext();
1379
        mctx.marshalDocument(object, "UTF-8", null, out);
1380
    }
1381
    
1382
    /**
1383
     * deserialize an object of type from is
1384
     * @param type the class of the object to serialize (i.e. SystemMetadata.class)
1385
     * @param is the stream to deserialize from
1386
     * @throws JiBXException
1387
     */
1388
    private Object deserializeServiceType(Class type, InputStream is)
1389
      throws JiBXException
1390
    {
1391
        IBindingFactory bfact = BindingDirectory.getFactory(type);
1392
        IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
1393
        Object o = (Object) uctx.unmarshalDocument(is, null);
1394
        return o;
1395
    }
1396
    
1397
    /**
1398
     * Earthgrid API > Query Service > Query Function : translates ecogrid query document to metacat query 
1399
     * then calls DBQuery > createResultDocument function and then again translate resultset to ecogrid resultset
1400
     * 
1401
     * NOTE:
1402
     *      This is the only method that uses EcoGrid classes for its implementation.  
1403
     *      It does so because it takes an EcoGrid Query as input, and outputs an
1404
     *      EcoGrid ResultSet document.  These documents are parsed by the auto-generated
1405
     *      EcoGrid classes from axis, and so we link to them here rather than re-inventing them.
1406
     *      This creates a circular dependency, because the Metacat classes are needed
1407
     *      to build the EcoGrid implementation, and the EcoGrid jars are needed to build this query()
1408
     *      method.  This circularity could be resolved by moving the EcoGrid classes
1409
     *      to Metacat directly.  As we transition away from EcoGrid SOAP methods in
1410
     *      favor of these REST interfaces, this circular dependency can be eliminated.
1411
     *        
1412
     * @throws Exception
1413
     */
1414
    private void query() throws Exception {
1415
        /*  This block commented out because of the EcoGrid circular dependency.
1416
         *  For now, query will not be supported until the circularity can be
1417
         *  resolved, probably by moving the ecogrid query syntax transformers
1418
         *  directly into the Metacat codebase.  MBJ 2010-02-03
1419
         
1420
        try {
1421
            EcogridQueryParser parser = new EcogridQueryParser(request
1422
                    .getReader());
1423
            parser.parseXML();
1424
            QueryType queryType = parser.getEcogridQuery();
1425
            EcogridJavaToMetacatJavaQueryTransformer queryTransformer = 
1426
                new EcogridJavaToMetacatJavaQueryTransformer();
1427
            QuerySpecification metacatQuery = queryTransformer
1428
                    .transform(queryType);
1429

    
1430
            DBQuery metacat = new DBQuery();
1431

    
1432
            boolean useXMLIndex = (new Boolean(PropertyService
1433
                    .getProperty("database.usexmlindex"))).booleanValue();
1434
            String xmlquery = "query"; // we don't care the query in resultset,
1435
            // the query can be anything
1436
            PrintWriter out = null; // we don't want metacat result, so set out null
1437

    
1438
            // parameter: queryspecification, user, group, usingIndexOrNot
1439
            StringBuffer result = metacat.createResultDocument(xmlquery,
1440
                    metacatQuery, out, username, groupNames, useXMLIndex);
1441

    
1442
            // create result set transfer       
1443
            String saxparser = PropertyService.getProperty("xml.saxparser");
1444
            MetacatResultsetParser metacatResultsetParser = new MetacatResultsetParser(
1445
                    new StringReader(result.toString()), saxparser, queryType
1446
                            .getNamespace().get_value());
1447
            ResultsetType records = metacatResultsetParser.getEcogridResult();
1448

    
1449
            System.out
1450
                    .println(EcogridResultsetTransformer.toXMLString(records));
1451
            response.setContentType("text/xml");
1452
            out = response.getWriter();
1453
            out.print(EcogridResultsetTransformer.toXMLString(records));
1454

    
1455
        } catch (Exception e) {
1456
            e.printStackTrace();
1457
        }*/
1458
        response.setContentType("text/xml");
1459
        response.setStatus(501);
1460
        PrintWriter out = response.getWriter();
1461
        out.print("<error>Query operation not yet supported by Metacat.</error>");
1462
        out.close();
1463
    }
1464
    
1465
    private String streamToString(InputStream is)
1466
    throws IOException
1467
    {
1468
        return IOUtil.toString(is);
1469
    }
1470

    
1471
    private InputStream stringToStream(String s)
1472
    throws IOException
1473
    {
1474
        ByteArrayInputStream bais = new ByteArrayInputStream(s.getBytes(MetaCatServlet.DEFAULT_ENCODING));
1475
        return bais;
1476
    }
1477
    
1478
    /**
1479
     * locate the boundary marker for an MMP
1480
     * @param is
1481
     * @return
1482
     * @throws IOException
1483
     */
1484
    protected static String[] findBoundaryString(InputStream is)
1485
        throws IOException
1486
    {
1487
        String[] endResult = new String[2];
1488
        String boundary = "";
1489
        String searchString = "boundary=";
1490
        boolean doneWithCurrentArray = false;
1491
        byte[] b = new byte[1024];
1492
        int numbytes = is.read(b, 0, 1024);
1493

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

    
1852
                // Check if the objectId exists
1853
                IdentifierManager im = IdentifierManager.getInstance();
1854
                if (im.identifierExists(guid)) {
1855
                    throw new IdentifierNotUnique("1000", "Identifier is already in use: " + guid);
1856
                }
1857

    
1858
                logMetacat.debug("Commence creation...");
1859
                IBindingFactory bfact =
1860
                    BindingDirectory.getFactory(SystemMetadata.class);
1861
                IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
1862
                SystemMetadata m = (SystemMetadata) uctx.unmarshalDocument(sysmeta, null);
1863

    
1864
                CrudService cs = CrudService.getInstance();
1865
                AuthToken token = new AuthToken(sessionId); 
1866
                cs.setParamsFromRequest(request);
1867
                Identifier id = new Identifier();
1868
                id.setValue(guid);
1869
                System.out.println("creating object with guid " + id.getValue());
1870
                Identifier rId = cs.create(token, id, object, m);
1871
                serializeServiceType(Identifier.class, rId, out);
1872
                
1873
            } else if (action.equals(FUNCTION_NAME_UPDATE)) { //handle updates
1874
                IdentifierManager im = IdentifierManager.getInstance();
1875
                CrudService cs = CrudService.getInstance();
1876
                Identifier obsoletedGuid = new Identifier();
1877
                Identifier id = new Identifier();
1878
                id.setValue(guid);
1879
                AuthToken token = new AuthToken(sessionId);
1880
                
1881
                //do some checks
1882
                if(params.get("obsoletedGuid") == null)
1883
                {
1884
                    throw new InvalidRequest("1202", "obsoletedGuid must be contained in the request parameters.");
1885
                }
1886
                //get the obsoletedGuid
1887
                String[] obsGuidS = params.get("obsoletedGuid");
1888
                obsoletedGuid.setValue(obsGuidS[0]);
1889
                
1890
                if (!im.identifierExists(obsoletedGuid.getValue())) 
1891
                {
1892
                    throw new InvalidRequest("1202", "The guid you are trying to update does not exist.");
1893
                }
1894
                
1895
                
1896
                logMetacat.debug("Commence update...");
1897
                
1898
                //get the systemmetadata
1899
                IBindingFactory bfact =
1900
                        BindingDirectory.getFactory(SystemMetadata.class);
1901
                    IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
1902
                    SystemMetadata m = (SystemMetadata) uctx.unmarshalDocument(sysmeta, null);
1903
                
1904
                //do the update
1905
                try
1906
                {
1907
                    cs.setParamsFromRequest(request);
1908
                    Identifier rId = cs.update(token, id, object, obsoletedGuid, m);
1909
                    serializeServiceType(Identifier.class, rId, out);
1910
                }
1911
                catch(NotFound e)
1912
                {
1913
                    throw new InvalidRequest("1202", "The guid you are trying to update does not exist.");
1914
                }
1915
                
1916
            } else {
1917
                throw new InvalidRequest("1000", "Operation must be create or update.");
1918
            }
1919
            
1920
            //clean up the MMP files
1921
            parts.get("systemmetadata").delete();
1922
            parts.get("object").delete();
1923
        } catch (NotAuthorized e) {
1924
            response.setStatus(500);
1925
            serializeException(e, out);
1926
        } catch (InvalidToken e) {
1927
            response.setStatus(500);
1928
            serializeException(e, out);
1929
        } catch (ServiceFailure e) {
1930
            response.setStatus(500);
1931
            serializeException(e, out);
1932
        } catch (IdentifierNotUnique e) {
1933
            response.setStatus(500);
1934
            serializeException(e, out);
1935
        } catch (UnsupportedType e) {
1936
            response.setStatus(500);
1937
            serializeException(e, out);
1938
        } catch (InsufficientResources e) {
1939
            response.setStatus(500);
1940
            serializeException(e, out);
1941
        } catch (InvalidSystemMetadata e) {
1942
            response.setStatus(500);
1943
            serializeException(e, out);
1944
        } catch (NotImplemented e) {
1945
            response.setStatus(500);
1946
            serializeException(e, out);
1947
        } catch (InvalidRequest e) {
1948
            response.setStatus(500);
1949
            serializeException(e, out);
1950
        } /*catch (MessagingException e) {
1951
            ServiceFailure sf = new ServiceFailure("1000", e.getMessage());
1952
            serializeException(sf, out);
1953
        } catch (IOException e) {
1954
            response.setStatus(500);
1955
            ServiceFailure sf = new ServiceFailure("1000", e.getMessage());
1956
            serializeException(sf, out);
1957
        }*/ catch (JiBXException e) {
1958
            response.setStatus(500);
1959
            e.printStackTrace(System.out);
1960
            InvalidSystemMetadata ism = new InvalidSystemMetadata("1080", e.getMessage());
1961
            serializeException(ism, out);
1962
        }
1963
        finally
1964
        {
1965
            if(parts != null)
1966
            {
1967
                Enumeration keys = parts.keys();
1968
                while(keys.hasMoreElements())
1969
                {
1970
                    String key = (String)keys.nextElement();
1971
                    File f = parts.get(key);
1972
                    f.delete();
1973
                }
1974
            }
1975
        }
1976
    }
1977

    
1978
    /**
1979
     * Handle delete 
1980
     * @param guid ID of data object to be deleted
1981
     * @throws IOException
1982
     */
1983
    private void deleteObject(String guid) throws IOException 
1984
    {
1985
        // Look up the localId for this global identifier
1986
        System.out.println("!!!!!!!!!!!!!!!!!deleting object " + guid);
1987
        IdentifierManager im = IdentifierManager.getInstance();
1988
        String localId = "";
1989
        OutputStream out = response.getOutputStream();
1990
        response.setStatus(200);
1991
        try {
1992
            localId = im.getLocalId(guid);
1993
        } catch (McdbDocNotFoundException e) {
1994
            NotFound nf = new NotFound("1340", "Document with guid " + guid + " not found.");
1995
            response.setStatus(404);
1996
            serializeException(nf, out);
1997
        }
1998
       
1999
        AuthToken token = new AuthToken(sessionId);
2000
        CrudService cs = CrudService.getInstance();
2001
        Identifier id = new Identifier();
2002
        id.setValue(guid);
2003
        try
2004
        {
2005
            System.out.println("Calling delete");
2006
            cs.delete(token, id);
2007
            serializeServiceType(Identifier.class, id, out);
2008
        } 
2009
        catch (NotAuthorized e) {
2010
            response.setStatus(500);
2011
            serializeException(e, out);
2012
        } catch (InvalidToken e) {
2013
            response.setStatus(500);
2014
            serializeException(e, out);
2015
        } catch (ServiceFailure e) {
2016
            response.setStatus(500);
2017
            serializeException(e, out);
2018
        } catch (NotImplemented e) {
2019
            response.setStatus(500);
2020
            serializeException(e, out);
2021
        } catch (InvalidRequest e) {
2022
            response.setStatus(500);
2023
            serializeException(e, out);
2024
        } catch(NotFound e) {
2025
            response.setStatus(500);
2026
            serializeException(e, out);
2027
        } catch(JiBXException e) {
2028
            response.setStatus(500);
2029
            serializeException(new ServiceFailure("1350", "JiBXException: " + e.getMessage()), out);
2030
        }
2031
        out.close();
2032
    }
2033
    
2034
    /**
2035
     * set the access perms on a document
2036
     * @throws IOException
2037
     */
2038
    private void setaccess() throws Exception
2039
    {
2040
        try
2041
        {
2042
            String guid = params.get("guid")[0];
2043
            Identifier id = new Identifier();
2044
            id.setValue(guid);
2045
            AuthToken token = new AuthToken(sessionId);
2046
            String principal = params.get("principal")[0];
2047
            String permission = params.get("permission")[0];
2048
            String permissionType = params.get("permissionType")[0];
2049
            String permissionOrder = params.get("permissionOrder")[0];
2050
            String setSystemMetadata = params.get("setsystemmetadata")[0];
2051
            boolean ssm = false;
2052
            if(setSystemMetadata.equals("true") || setSystemMetadata.equals("TRUE") ||
2053
                    setSystemMetadata.equals("yes"))
2054
            {
2055
                ssm = true;
2056
            }
2057
            CrudService cs = CrudService.getInstance();
2058
            //TODO: remove the setsystemmetadata param and set this so the systemmetadata always gets set
2059
            cs.setAccess(token, id, principal, permission, permissionType, permissionOrder, ssm);
2060
        }
2061
        catch(Exception e)
2062
        {
2063
            response.setStatus(500);
2064
            printError("Error setting access in ResourceHandler: " + e.getMessage(), response);
2065
            throw e;
2066
        }
2067
    }
2068

    
2069
    /**
2070
     * Earthgrid API > Authentication Service > Login Function : calls MetacatHandler > handleLoginAction
2071
     * 
2072
     * @throws IOException
2073
     */
2074
    private void login() throws IOException {
2075
        PrintWriter out = response.getWriter();
2076
        response.setStatus(200);
2077
        response.setContentType("text/xml");
2078
        handler.handleLoginAction(out, params, request, response);
2079
        out.close();
2080
    }
2081

    
2082
    /**
2083
     * Earthgrid API > Authentication Service > Logout Function : calls MetacatHandler > handleLogoutAction
2084
     * 
2085
     * @throws IOException
2086
     */
2087
    private void logout() throws IOException {
2088
        PrintWriter out = response.getWriter();
2089
        response.setStatus(200);
2090
        response.setContentType("text/xml");
2091
        handler.handleLogoutAction(out, params, request, response);
2092
        out.close();
2093
    }
2094

    
2095
    /**
2096
     * Prints xml response
2097
     * @param message Message to be displayed
2098
     * @param response Servlet response that xml message will be printed 
2099
     * */
2100
    private void printError(String message, HttpServletResponse response) {
2101
        try {
2102
            logMetacat.error("ResourceHandler: Printing error to servlet response: " + message);
2103
            PrintWriter out = response.getWriter();
2104
            response.setContentType("text/xml");
2105
            out.println("<?xml version=\"1.0\"?>");
2106
            out.println("<error>");
2107
            out.println(message);
2108
            out.println("</error>");
2109
            out.close();
2110
        } catch (IOException e) {
2111
            e.printStackTrace();
2112
        }
2113
    }
2114
    
2115
    /**
2116
     * serialize a D1 exception using jibx
2117
     * @param e
2118
     * @param out
2119
     */
2120
    private void serializeException(BaseException e, OutputStream out) {
2121
        // TODO: Use content negotiation to determine which return format to use
2122
        response.setContentType("text/xml");
2123
        response.setStatus(e.getCode());
2124
        
2125
        logMetacat.error("ResourceHandler: Serializing exception with code " + e.getCode() + ": " + e.getMessage());
2126
        e.printStackTrace();
2127
        
2128
        try {
2129
            IOUtils.write(e.serialize(BaseException.FMT_XML), out);
2130
        } catch (IOException e1) {
2131
            logMetacat.error("Error writing exception to stream. " 
2132
                    + e1.getMessage());
2133
        }
2134
    }
2135
    
2136
    /**
2137
     * create a new ServiceMethod declaration
2138
     * @param name
2139
     * @param rest
2140
     * @param implemented
2141
     * @return
2142
     */
2143
    private ServiceMethod getServiceMethod(String name, String rest, boolean implemented)
2144
    {
2145
        ServiceMethod sm = new ServiceMethod();
2146
        sm.setImplemented(implemented);
2147
        sm.setName(name);
2148
        sm.setRest(rest);
2149
        return sm;
2150
    }
2151

    
2152
}
(4-4/5)