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.dataone.service.types.util.ServiceTypeUtil;
62
import org.jibx.runtime.BindingDirectory;
63
import org.jibx.runtime.IBindingFactory;
64
import org.jibx.runtime.IMarshallingContext;
65
import org.jibx.runtime.IUnmarshallingContext;
66
import org.jibx.runtime.JiBXException;
67

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
940
        String name = null;
941
        String[] value = null;
942
        Enumeration paramlist = request.getParameterNames();
943
        while (paramlist.hasMoreElements()) {
944
            name = (String) paramlist.nextElement();
945
            value = request.getParameterValues(name);
946
            params.put(name, value);
947
        }
948
    }
949

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

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

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

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

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

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

    
1099
            out.println("<?xml version=\"1.0\"?>");
1100
            out.print("<next-revision>");
1101
            out.print(revision);
1102
            out.print("</next-revision>");
1103

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

    
1113
        out.close();
1114
    }
1115

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

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

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

    
1421
            DBQuery metacat = new DBQuery();
1422

    
1423
            boolean useXMLIndex = (new Boolean(PropertyService
1424
                    .getProperty("database.usexmlindex"))).booleanValue();
1425
            String xmlquery = "query"; // we don't care the query in resultset,
1426
            // the query can be anything
1427
            PrintWriter out = null; // we don't want metacat result, so set out null
1428

    
1429
            // parameter: queryspecification, user, group, usingIndexOrNot
1430
            StringBuffer result = metacat.createResultDocument(xmlquery,
1431
                    metacatQuery, out, username, groupNames, useXMLIndex);
1432

    
1433
            // create result set transfer       
1434
            String saxparser = PropertyService.getProperty("xml.saxparser");
1435
            MetacatResultsetParser metacatResultsetParser = new MetacatResultsetParser(
1436
                    new StringReader(result.toString()), saxparser, queryType
1437
                            .getNamespace().get_value());
1438
            ResultsetType records = metacatResultsetParser.getEcogridResult();
1439

    
1440
            System.out
1441
                    .println(EcogridResultsetTransformer.toXMLString(records));
1442
            response.setContentType("text/xml");
1443
            out = response.getWriter();
1444
            out.print(EcogridResultsetTransformer.toXMLString(records));
1445

    
1446
        } catch (Exception e) {
1447
            e.printStackTrace();
1448
        }*/
1449
        response.setContentType("text/xml");
1450
        response.setStatus(501);
1451
        PrintWriter out = response.getWriter();
1452
        out.print("<error>Query operation not yet supported by Metacat.</error>");
1453
        out.close();
1454
    }
1455
    
1456
    private String streamToString(InputStream is)
1457
    throws IOException
1458
    {
1459
        return IOUtil.toString(is);
1460
    }
1461

    
1462
    private InputStream stringToStream(String s)
1463
    throws IOException
1464
    {
1465
        ByteArrayInputStream bais = new ByteArrayInputStream(s.getBytes(MetaCatServlet.DEFAULT_ENCODING));
1466
        return bais;
1467
    }
1468
    
1469
    /**
1470
     * locate the boundary marker for an MMP
1471
     * @param is
1472
     * @return
1473
     * @throws IOException
1474
     */
1475
    protected static String[] findBoundaryString(InputStream is)
1476
        throws IOException
1477
    {
1478
        String[] endResult = new String[2];
1479
        String boundary = "";
1480
        String searchString = "boundary=";
1481
        boolean doneWithCurrentArray = false;
1482
        byte[] b = new byte[1024];
1483
        int numbytes = is.read(b, 0, 1024);
1484

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

    
1843
                // Check if the objectId exists
1844
                IdentifierManager im = IdentifierManager.getInstance();
1845
                if (im.identifierExists(guid)) {
1846
                    throw new IdentifierNotUnique("1000", "Identifier is already in use: " + guid);
1847
                }
1848

    
1849
                logMetacat.debug("Commence creation...");
1850
                IBindingFactory bfact =
1851
                    BindingDirectory.getFactory(SystemMetadata.class);
1852
                IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
1853
                SystemMetadata m = (SystemMetadata) uctx.unmarshalDocument(sysmeta, null);
1854

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

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

    
2060
    /**
2061
     * Earthgrid API > Authentication Service > Login Function : calls MetacatHandler > handleLoginAction
2062
     * 
2063
     * @throws IOException
2064
     */
2065
    private void login() throws IOException {
2066
        PrintWriter out = response.getWriter();
2067
        response.setStatus(200);
2068
        response.setContentType("text/xml");
2069
        handler.handleLoginAction(out, params, request, response);
2070
        out.close();
2071
    }
2072

    
2073
    /**
2074
     * Earthgrid API > Authentication Service > Logout Function : calls MetacatHandler > handleLogoutAction
2075
     * 
2076
     * @throws IOException
2077
     */
2078
    private void logout() throws IOException {
2079
        PrintWriter out = response.getWriter();
2080
        response.setStatus(200);
2081
        response.setContentType("text/xml");
2082
        handler.handleLogoutAction(out, params, request, response);
2083
        out.close();
2084
    }
2085

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

    
2143
}
(4-4/5)