Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *  Copyright: 2000 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.util.*;
27

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

    
39

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

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

    
76
import org.dataone.service.streaming.util.StreamUtil;
77

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

    
152
 * </ul>
153
 * </li>
154
 * 
155
 * <li>
156
 * <h3>EarthGrid Identifier Service</h3><br/>
157
 * 
158
 * <ul>
159
 * <li><h3>isRegistered: </h3>      <br/>
160
 * <b>REST URL:</b> <code>GET, [context-root]/identifier/[doc-id]?op=isregistered</code>   <br/>
161
 * <b>Returns:</b> message in XML format<br/><br/>
162
 * </li>
163

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

    
191
    /**HTTP Verb GET*/
192
    public static final byte GET = 1;
193
    /**HTTP Verb POST*/
194
    public static final byte POST = 2;
195
    /**HTTP Verb PUT*/
196
    public static final byte PUT = 3;
197
    /**HTTP Verb DELETE*/
198
    public static final byte DELETE = 4;
199
    /**HTTP Verb HEAD*/
200
    public static final byte HEAD = 5;
201

    
202
    /*
203
     * API Resources
204
     */
205
    private static final String RESOURCE_OBJECTS = "object";
206
    private static final String RESOURCE_META = "meta";
207
    private static final String RESOURCE_SESSION = "session";
208
    private static final String RESOURCE_IDENTIFIER = "identifier";
209
    private static final String RESOURCE_LOG = "log";
210
    private static final String RESOURCE_CHECKSUM = "checksum";
211
    private static final String RESOURCE_MONITOR = "monitor";
212
    private static final String RESOURCE_BASE_URL = "d1";
213

    
214
    /*
215
     * API Functions used as URL parameters
216
     */
217
    private static final String FUNCTION_KEYWORD = "op";
218
    private static final String FUNCTION_NAME_LOGIN = "login";
219
    private static final String FUNCTION_NAME_LOGOUT = "logout";
220
    private static final String FUNCTION_NAME_SET_ACCESS = "setaccess";
221
    private static final String FUNCTION_NAME_ISREGISTERED = "isregistered";
222
    private static final String FUNCTION_NAME_GETALLDOCS = "getalldocids";
223
    private static final String FUNCTION_NAME_GETNEXTREV = "getnextrevision";
224
    private static final String FUNCTION_NAME_GETNEXTOBJ = "getnextobject";
225
    private static final String FUNCTION_NAME_INSERT = "insert";
226
    private static final String FUNCTION_NAME_UPDATE = "update";
227
    private static final String FUNCTION_NAME_GENERATE_MISSING_SYSTEM_METADATA = "generatemissingsystemmetadata";
228

    
229
    private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
230
    
231
    private ServletContext servletContext;
232
    private Logger logMetacat;
233
    private MetacatHandler handler;
234
    private HttpServletRequest request;
235
    private HttpServletResponse response;
236
    private String username;
237
    private String password;
238
    private String sessionId;
239
    private String[] groupNames;
240

    
241
    private Hashtable<String, String[]> params;
242

    
243
    /**Initializes new instance by setting servlet context,request and response*/
244
    public ResourceHandler(ServletContext servletContext,
245
            HttpServletRequest request, HttpServletResponse response) {
246
        this.servletContext = servletContext;
247
        this.request = request;
248
        this.response = response;
249
    }
250

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

    
279
            if (resource != null) {
280
                //resource = request.getServletPath().substring(1);
281

    
282
                params = new Hashtable<String, String[]>();
283
                initParams();
284

    
285
                Timer timer = new Timer();
286
                handler = new MetacatHandler(timer);
287

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

    
334
                } else if (resource.equals(RESOURCE_OBJECTS)) {
335
                    System.out.println("Using resource 'object'");
336
                    logMetacat.debug("D1 Rest: Starting resource processing...");
337
                    loadSessionData();
338

    
339
                    String objectId = request.getPathInfo();
340
                    if (objectId != null && objectId.length() > 1) 
341
                    {
342
                        objectId = request.getPathInfo().substring(1);
343
                    }
344
                    else
345
                    {
346
                        objectId = null;
347
                    }
348
                    
349
                    System.out.println("objectId in ReasourceHandler.handle: " + objectId);
350

    
351
                    logMetacat.debug("verb:" + httpVerb);
352

    
353
                    if (httpVerb == GET) {
354
                        getObject(objectId);
355
                        status = true;
356
                    } else if (httpVerb == POST) {
357
                        putObject(objectId, FUNCTION_NAME_INSERT);
358
                        status = true;
359
                    } else if (httpVerb == PUT) {
360
                        putObject(objectId, FUNCTION_NAME_UPDATE);
361
                        status = true;
362
                    } else if (httpVerb == DELETE) {
363
                        deleteObject(objectId);
364
                        status = true;
365
                    } else if (httpVerb == HEAD) {
366
                        describeObject(objectId);
367
                        status = true;
368
                    }
369
                    
370

    
371
                } else if (resource.equals(RESOURCE_IDENTIFIER)) {
372
                    System.out.println("Using resource 'identifier'");
373
                    String identifierId = request.getPathInfo();
374
                    if (identifierId != null && identifierId.length() > 1)
375
                        identifierId = request.getPathInfo().substring(1); //trim the slash
376

    
377
                    if (httpVerb == GET) {
378
                        String op = params.get(FUNCTION_KEYWORD)[0];
379
                        if (op.equals(FUNCTION_NAME_ISREGISTERED)) {
380
                            isRegistered(identifierId);
381
                            status = true;
382
                        } else if (op.equals(FUNCTION_NAME_GETALLDOCS)) {
383
                            getAllDocIds();
384
                            status = true;
385
                        } else if (op.equals(FUNCTION_NAME_GETNEXTREV)) {
386
                            getNextRevision(identifierId);
387
                            status = true;
388
                        } else if (op.equals(FUNCTION_NAME_GETNEXTOBJ)) {
389
                            getNextObject();
390
                            status = true;
391
                        } 
392

    
393
                    } else if (httpVerb == PUT) {
394
                        //Earthgrid API > Identifier Service > addLSID Function 
395
                        response.setStatus(501);
396
                        printError(
397
                                "This method is not supported by metacat.  To "
398
                                + "add a new LSID, add a document to metacat.",
399
                                response);
400
                        status = true;
401
                    }
402

    
403
                } else if (resource.equals(RESOURCE_LOG)) {
404
                    System.out.println("Using resource 'log'");
405
                    //handle log events
406
                    if(httpVerb == GET)
407
                    {
408
                        getLog();
409
                        status = true;
410
                    }
411
                    else
412
                    {
413
                        //change to D1 spec for specifying which http methods are allowed for a resource
414
                        response.setStatus(501);
415
                        printError("POST, PUT, DELETE is not supported for logs.", response);
416
                        status = true;
417
                    }
418

    
419
                } else if(resource.equals(RESOURCE_CHECKSUM)) {
420
                    System.out.println("Using resource 'checksum'");
421
                    //handle checksum requests
422
                    if(httpVerb == GET)
423
                    {
424
                        String guid = null;
425
                        String checksumAlgorithm = "MD5";
426
                    
427
                        try
428
                        {
429
                           guid = params.get("id")[0];
430
                        }
431
                        catch(Exception e)
432
                        {
433
                            throw new InvalidRequest("1402", "Incorrect parameters passed to getChecksum");
434
                        }
435
                        
436
                        Identifier guidid = new Identifier();
437
                        guidid.setValue(guid);
438
                        AuthToken token = new AuthToken(sessionId);
439
                        try
440
                        {
441
                            checksumAlgorithm = params.get("checksumAlgorithm")[0];
442
                        }
443
                        catch(Exception e)
444
                        {
445
                            //do nothing.  default to MD5
446
                        }
447
                        System.out.println("getting checksum for object " + guid +
448
                                " with algorithm " + checksumAlgorithm);
449
                        try
450
                        {
451
                            Checksum c = CrudService.getInstance().getChecksum(token, guidid, checksumAlgorithm);
452
                            System.out.println("got checksum " + c.getValue());
453
                            response.setStatus(200);
454
                            System.out.println("serializing response");
455
                            serializeServiceType(Checksum.class, c, response.getOutputStream());
456
                            System.out.println("done serializing response.");
457
                        }
458
                        catch(NotAuthorized na)
459
                        {
460
                            na.setDetail_code("1400");
461
                            serializeException(na, response.getOutputStream());
462
                        }
463
                        catch(NotFound nf)
464
                        {
465
                            nf.setDetail_code("1420");
466
                            serializeException(nf, response.getOutputStream());
467
                        }
468
                        catch(InvalidRequest ir)
469
                        {
470
                            ir.setDetail_code("1402");
471
                            serializeException(ir, response.getOutputStream());
472
                        }
473
                        catch(ServiceFailure sf)
474
                        {
475
                            sf.setDetail_code("1410");
476
                            serializeException(sf, response.getOutputStream());
477
                        }
478
                        catch(InvalidToken it)
479
                        {
480
                            it.setDetail_code("1430");
481
                            serializeException(it, response.getOutputStream());
482
                        }
483
                        status = true;
484
                    }
485
                } else if(resource.equals(RESOURCE_MONITOR)) {
486
                    //health monitoring calls
487
                    System.out.println("processing monitor request");
488
                    String pathInfo = request.getPathInfo();
489
                    if(httpVerb == GET)
490
                    {
491
                        System.out.println("verb is GET");
492
                        System.out.println("pathInfo is " + pathInfo);
493
                        pathInfo = pathInfo.substring(1);
494
                        HealthService hs = new HealthService(request, response);
495
                        if (pathInfo.toLowerCase().equals("ping")) {
496
                            System.out.println("processing ping request");
497
                            hs.ping();
498
                        } else if (pathInfo.toLowerCase().equals("status")) {
499
                            System.out.println("processing status request");
500
                            hs.getStatus();
501
                        } else if (pathInfo.toLowerCase().equals("object")) {
502
                            System.out.println("processing object request");
503
                            boolean day = false;
504
                            Identifier pid = null;
505
                            String url = null;
506
                            ObjectFormat of = null;
507
                            Date time = null;
508
                            
509
                            if(params.containsKey("day"))
510
                            {
511
                               day = true; 
512
                            }
513
                            if(params.containsKey("pid"))
514
                            {
515
                                String id = params.get("pid")[0];
516
                                pid = new Identifier();
517
                                pid.setValue(id);
518
                            }
519
                            if(params.containsKey("url"))
520
                            {
521
                                url = params.get("url")[0];
522
                            }
523
                            if(params.containsKey("format"))
524
                            {
525
                                String format = params.get("format")[0];
526
                                of = ObjectFormat.convert(format);
527
                            }
528
                            if(params.containsKey("time"))
529
                            {
530
                                String t = params.get("time")[0];
531
                                time = dateFormat.parse(t);
532
                            }
533
                            
534
                            hs.getObjectStatistics(day, pid, url, of, time);
535
                        } else if (pathInfo.toLowerCase().equals("event")) {
536
                            System.out.println("processing event request");
537
                            boolean day = false;
538
                            Identifier pid = null;
539
                            Date created = null;
540
                            ObjectFormat of = null;
541
                            Date time = null;
542
                            String ipAddress = null;
543
                            String event = null;
544
                            
545
                            if(params.containsKey("day"))
546
                            {
547
                               day = true; 
548
                            }
549
                            if(params.containsKey("pid"))
550
                            {
551
                                String id = params.get("pid")[0];
552
                                pid = new Identifier();
553
                                pid.setValue(id);
554
                            }
555
                            if(params.containsKey("created"))
556
                            {
557
                                String t = params.get("created")[0];
558
                                created = dateFormat.parse(t);
559
                            }
560
                            if(params.containsKey("format"))
561
                            {
562
                                String format = params.get("format")[0];
563
                                of = ObjectFormat.convert(format);
564
                            }
565
                            if(params.containsKey("eventtime"))
566
                            {
567
                                String t = params.get("eventtime")[0];
568
                                time = dateFormat.parse(t);
569
                            }
570
                            if(params.containsKey("ip_address"))
571
                            {
572
                                ipAddress = params.get("ip_address")[0];
573
                            }
574
                            if(params.containsKey("event"))
575
                            {
576
                                event = params.get("event")[0];
577
                            }
578
                            
579
                            hs.getOperationStatistics(day, pid, of, created, time, ipAddress, event);
580
                        }
581
                    }
582
                    status = true;
583
                }
584
                    
585
                if (!status)
586
                {
587
                    response.setStatus(400);
588
                    printError("Incorrect parameters!", response);
589
                }
590
            } else {
591
                response.setStatus(400);
592
                printError("Incorrect resource!", response);
593
            }
594
        } catch (Exception e) {
595
            logMetacat.error(e.getMessage());
596
            e.printStackTrace();
597
        }
598
    }
599
    
600
    /**
601
     * create the root node registry response.  
602
     * @throws JiBXException
603
     * @throws IOException
604
     */
605
    private void createNodeResponse() 
606
        throws JiBXException, IOException
607
    {
608
        NodeList nl = new NodeList();
609
        Node n = new Node();
610
        NodeReference nr = new NodeReference();
611
        nr.setValue(request.getRequestURL().toString());
612
        n.setIdentifier(nr);
613
        n.setBaseURL(request.getRequestURL().toString());
614
        n.setDescription("Metacat DataONE Node");
615
        n.setName("Metacat");
616
        n.setType(NodeType.convert("mn"));
617
        
618
        //create the services
619
        Service mnCrud03 = new Service();
620
        mnCrud03.setName("Metacat MN_Crud Services Version 0.3");
621
        mnCrud03.setVersion("0.3");
622
        
623
        Service mnCrud04 = new Service();
624
        mnCrud04.setName("Metacat MN_Crud Services Version 0.4");
625
        mnCrud04.setVersion("0.4");
626
        
627
        Service mnCrud09 = new Service();
628
        mnCrud09.setName("Metacat MN_Crud Services Version 0.9");
629
        mnCrud09.setVersion("0.9");
630
        
631
        Service mnReplication03 = new Service();
632
        mnReplication03.setName("Metcat MN_Replication Version 0.3");
633
        mnReplication03.setVersion("0.3");
634
        
635
        Service mnHealth04 = new Service();
636
        mnHealth04.setName("Metacat MN_Health Version 0.4");
637
        mnHealth04.setVersion("0.4");
638
        
639
        Service mnHealth06 = new Service();
640
        mnHealth06.setName("Metacat MN_Health Version 0.6");
641
        mnHealth06.setVersion("0.6");
642
        
643
        Service mnAuthentication07 = new Service();
644
        mnAuthentication07.setName("Metacat MN_Authentication Version 0.7");
645
        mnAuthentication07.setVersion("0.7");
646
        
647
        Service mnAuthorization07 = new Service();
648
        mnAuthorization07.setName("Metacat MN_Authorization Version 0.7");
649
        mnAuthorization07.setVersion("0.7");
650
        
651
                                    //name, rest, implemented
652
        mnCrud03.addMethod(getServiceMethod("MN_crud.get()", "/object/<guid>", true));
653
        mnCrud03.addMethod(getServiceMethod("MN_crud.getSystemMetadata()", "/meta/<guid>", true));
654
        mnCrud04.addMethod(getServiceMethod("MN_crud.create()", "/object/<guid>", true));
655
        mnCrud04.addMethod(getServiceMethod("MN_crud.update()", "/object/<guid>", true));
656
        mnCrud09.addMethod(getServiceMethod("MN_crud.delete()", "/object/<guid>", true));
657
        mnCrud03.addMethod(getServiceMethod("MN_crud.describe()", "/object/<guid>", true));
658
        mnCrud03.addMethod(getServiceMethod("MN_crud.getChecksum()", "/checksum/<guid>", true));
659
        mnCrud03.addMethod(getServiceMethod("MN_crud.getLogRecords()", "/log", true));
660
        mnReplication03.addMethod(getServiceMethod("MN_replication.listObjects()", "/object", true));
661
        mnHealth04.addMethod(getServiceMethod("MN_health.ping()", "/health/ping", false));
662
        mnHealth04.addMethod(getServiceMethod("MN_health.getObjectStatistics()", "/monitor/object/<guid>", false));
663
        mnHealth06.addMethod(getServiceMethod("MN_health.getStatus()", "/health/status", false));
664
        mnAuthentication07.addMethod(getServiceMethod("MN_authentication.login()", "/account/login", false));
665
        mnAuthentication07.addMethod(getServiceMethod("MN_authentication.logout()", "/account/logout", false));
666
        mnAuthorization07.addMethod(getServiceMethod("MN_authorization.isAuthorized()", "/isAuthorized/<guid>", false));
667
        
668
        Services ss = new Services();
669
        ss.addService(mnCrud03);
670
        ss.addService(mnCrud04);
671
        ss.addService(mnCrud09);
672
        ss.addService(mnReplication03);
673
        ss.addService(mnHealth04);
674
        ss.addService(mnHealth06);
675
        ss.addService(mnAuthentication07);
676
        ss.addService(mnAuthorization07);
677
        nl.addNode(n);
678
        response.setContentType("text/xml");
679
        response.setStatus(200);
680
        serializeServiceType(NodeList.class, nl, response.getOutputStream());
681
    }
682
    
683
    /**
684
     * MN_crud.describe()
685
     * http://mule1.dataone.org/ArchitectureDocs/mn_api_crud.html#MN_crud.describe
686
     * @param guid
687
     */
688
    private void describeObject(String guid)
689
    {
690
        Logger logMetacat = Logger.getLogger(ResourceHandler.class);
691
        OutputStream out = null;
692
        try
693
        {
694
            out = response.getOutputStream();
695
        }
696
        catch(Exception e)
697
        {
698
            logMetacat.error("Error getting output stream in ResourceHandler.describeObject: " + e.getMessage());
699
            return;
700
        }
701
        response.setStatus(200);
702
        response.setContentType("text/xml");
703
        AuthToken token = new AuthToken(sessionId);
704
        CrudService cs = CrudService.getInstance();
705
        Identifier id = new Identifier();
706
        id.setValue(guid);
707
        try
708
        {
709
            DescribeResponse dr = cs.describe(token, id);
710
            DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SZ");
711
            response.addHeader("guid", guid);
712
            response.addHeader("checksum", dr.getDataONE_Checksum().getValue());
713
            response.addHeader("checksum_algorithm", dr.getDataONE_Checksum().getAlgorithm().name());
714
            response.addHeader("content_length", dr.getContent_Length() + "");
715
            response.addHeader("last_modified", dateFormat.format(dr.getLast_Modified()));
716
            response.addHeader("format", dr.getDataONE_ObjectFormat().toString());
717
        }
718
        catch(InvalidRequest ir)
719
        {
720
            serializeException(ir, out);
721
        }
722
        catch(NotImplemented ni)
723
        {
724
            serializeException(ni, out);
725
        }
726
        catch(NotAuthorized na)
727
        {
728
            serializeException(na, out);
729
        }
730
        catch(ServiceFailure sf)
731
        {
732
            serializeException(sf, out);
733
        }
734
        catch(NotFound nf)
735
        {
736
            serializeException(nf, out);
737
        }
738
        catch(InvalidToken it)
739
        {
740
            serializeException(it, out);
741
        }
742
    }
743
    
744
    /**
745
     * get the logs from the CrudService based on passed params.  Available 
746
     * params are token, fromDate, toDate, event.  See 
747
     * http://mule1.dataone.org/ArchitectureDocs/mn_api_crud.html#MN_crud.getLogRecords
748
     * for more info
749
     */
750
    private void getLog()
751
    {
752
        OutputStream out = null;
753
        try
754
        {
755
            out = response.getOutputStream();
756
            response.setStatus(200);
757
            response.setContentType("text/xml");
758
            AuthToken token = new AuthToken(sessionId);
759
            String fromDateS = params.get("fromDate")[0];
760
            System.out.println("param fromDateS: " + fromDateS);
761
            Date fromDate = null;
762
            String toDateS = params.get("toDate")[0];
763
            System.out.println("param toDateS: " + toDateS);
764
            Date toDate = null;
765
            String eventS = params.get("event")[0];
766
            Event event = null;
767
            if(fromDateS != null)
768
            {
769
                //fromDate = dateFormat.parse(fromDateS);
770
                fromDate = parseDateAndConvertToGMT(fromDateS);
771
            }
772
            if(toDateS != null)
773
            {
774
                //toDate = dateFormat.parse(toDateS);
775
                toDate = parseDateAndConvertToGMT(toDateS);
776
            }
777
            if(eventS != null)
778
            {
779
                event = Event.convert(eventS);
780
            }
781
            System.out.println("fromDate: " + fromDate + " toDate: " + toDate);
782
            
783
            System.out.println("calling crudservice.getLogRecords");
784
            Log log = CrudService.getInstance().getLogRecords(token, fromDate, toDate, event);
785
            serializeServiceType(Log.class, log, out);
786
        }
787
        catch(Exception e)
788
        {
789
            String msg = "Could not get logs from CrudService: " + e.getMessage();
790
            response.setStatus(500);
791
            ServiceFailure sf = new ServiceFailure("1490", msg);
792
            logMetacat.error(msg);
793
            e.printStackTrace();
794
            serializeException(sf, out);
795
        }
796
    }
797
    
798
    /**
799
     *  copies request parameters to a hashtable which is given as argument to native metacathandler functions  
800
     */
801
    private void initParams() {
802

    
803
        String name = null;
804
        String[] value = null;
805
        Enumeration paramlist = request.getParameterNames();
806
        while (paramlist.hasMoreElements()) {
807
            name = (String) paramlist.nextElement();
808
            value = request.getParameterValues(name);
809
            params.put(name, value);
810
        }
811
    }
812

    
813
    /**
814
     * 
815
     * Load user details of metacat session from the request 
816
     * 
817
     */
818
    private void loadSessionData()
819
      throws Exception
820
    {
821
        SessionData sessionData = RequestUtil.getSessionData(request);
822
        try
823
        {
824
            username = null;
825
            password = null;
826
            groupNames = null;
827
            sessionId = null;
828
            
829
            boolean validSession = false;
830
            SessionService ss = SessionService.getInstance();
831
            System.out.println("sessionData: " + sessionData);
832
            if(sessionData == null)
833
            {
834
                username = "public";
835
                sessionId = "0";
836
                System.out.println("sessiondata is null.  Creating a public session.");
837
                return;
838
            }
839
            
840
            System.out.println("username: " + sessionData.getUserName());
841
            System.out.println("sessionid: " + sessionData.getId());
842
            //validate the session
843
            if(ss.isSessionRegistered(sessionData.getId()) && 
844
               !(sessionData.getUserName().equals("public") || sessionData.getId().equals("0")))
845
            {
846
                validSession = true;
847
            }
848
            
849
            if(validSession)
850
            {
851
                //if the session is valid, set these variables
852
                username = sessionData.getUserName();
853
                password = sessionData.getPassword();
854
                groupNames = sessionData.getGroupNames();
855
                sessionId = sessionData.getId();
856
                System.out.println("setting sessionid to " + sessionId);
857
                System.out.println("username: " + username);
858
            }
859
            
860
            //if the session is not valid or the username is null, set
861
            //username to public
862
            if (username == null) 
863
            {
864
                System.out.println("setting username to public.");
865
                username = "public";
866
            }
867
        }
868
        catch(Exception e)
869
        {
870
            e.printStackTrace();
871
            throw new Exception("Could not load the session data: " + e.getMessage());
872
        }
873
    }
874
    
875
    /**
876
     * generate missing system metadata for any science metadata objects
877
     * that don't already have it. https://trac.dataone.org/ticket/591
878
     * 
879
     * called with POST meta/?op=generatemissingsystemmetadata
880
     */
881
    private void generateMissingSystemMetadata()
882
    {
883
        AuthToken token = new AuthToken(sessionId);
884
        CrudService.getInstance().generateMissingSystemMetadata(token);
885
    }
886

    
887
    /**
888
     *  Earthgrid API > Identifier Service > isRegistered Function : 
889
     *  calls MetacatHandler > handleIdIsRegisteredAction
890
     * @param guid
891
     * @throws IOException
892
     */
893
    private void isRegistered(String guid) throws IOException
894
    {
895
        
896
        // Look up the localId for this guid
897
        IdentifierManager im = IdentifierManager.getInstance();
898
        String localId = "";
899
        try {
900
            localId = im.getLocalId(guid);
901
        } catch (McdbDocNotFoundException e) {
902
            // TODO: Need to return the proper DataONE exception
903
        }
904
        
905
        params.put("docid", new String[] { localId });
906
        PrintWriter out = response.getWriter();
907
        response.setStatus(200);
908
        response.setContentType("text/xml");
909
        handler.handleIdIsRegisteredAction(out, params, response);
910
        out.close();
911
    }
912

    
913
    /**
914
     * Earthgrid API > Identifier Service > getAllDocIds Function : 
915
     * calls MetacatHandler > handleGetAllDocidsAction
916
     * @throws IOException
917
     */
918
    private void getAllDocIds() throws IOException {
919
        PrintWriter out = response.getWriter();
920
        response.setStatus(200);
921
        response.setContentType("text/xml");
922
        handler.handleGetAllDocidsAction(out, params, response);
923
        out.close();
924
    }
925

    
926
    /**
927
     * Earthgrid API > Identifier Service > getNextRevision Function : 
928
     * calls MetacatHandler > handleGetRevisionAndDocTypeAction
929
     * @param guid
930
     * @throws IOException
931
     */
932
    private void getNextRevision(String guid) throws IOException 
933
    {
934
        params.put("docid", new String[] { guid });
935
        PrintWriter out = response.getWriter();
936
        response.setStatus(200);
937
        response.setContentType("text/xml");
938
        //handler.handleGetRevisionAndDocTypeAction(out, params);
939

    
940
        try {
941
            // Make sure there is a docid
942
            if (guid == null || guid.equals("")) {
943
                throw new Exception("User didn't specify docid!");
944
            }
945

    
946
            // Look up the localId for this guid
947
            IdentifierManager im = IdentifierManager.getInstance();
948
            String localId = "";
949
            try {
950
                localId = im.getLocalId(guid);
951
            } catch (McdbDocNotFoundException e) {
952
                // TODO: Need to return the proper DataONE exception
953
            }
954
           
955
            // Create a DBUtil object
956
            DBUtil dbutil = new DBUtil();
957
            // Get a rev and doctype
958
            String revAndDocType = dbutil
959
                    .getCurrentRevisionAndDocTypeForGivenDocument(localId);
960
            int revision = Integer.parseInt(revAndDocType.split(";")[0]) + 1;
961

    
962
            out.println("<?xml version=\"1.0\"?>");
963
            out.print("<next-revision>");
964
            out.print(revision);
965
            out.print("</next-revision>");
966

    
967
        } catch (Exception e) {
968
            // Handle exception
969
            response.setStatus(500);
970
            out.println("<?xml version=\"1.0\"?>");
971
            out.println("<error>");
972
            out.println(e.getMessage());
973
            out.println("</error>");
974
        }
975

    
976
        out.close();
977
    }
978

    
979
    /**
980
     * Earthgrid API > Identifier Service > getNextObject Function : 
981
     * calls MetacatHandler > handleGetMaxDocidAction
982
     * @throws IOException
983
     */
984
    private void getNextObject() throws IOException {
985
        PrintWriter out = response.getWriter();
986
        response.setStatus(200);
987
        response.setContentType("text/xml");
988
        handler.handleGetMaxDocidAction(out, params, response);
989
        out.close();
990
    }
991

    
992
    /**
993
     * Implements REST version of DataONE CRUD API --> get
994
     * @param guid ID of data object to be read
995
     */
996
    private void getObject(String guid) {
997
        CrudService cs = CrudService.getInstance();
998
        cs.setParamsFromRequest(request);
999
        AuthToken token = new AuthToken(sessionId);
1000
        OutputStream out = null;
1001
        try {
1002
            out = response.getOutputStream();
1003
            response.setStatus(200);
1004
            response.setContentType("text/xml");
1005
            if(guid != null)
1006
            { //get a specific document                
1007
                Identifier id = new Identifier();
1008
                id.setValue(guid);
1009
                try
1010
                {
1011
                    if(token == null)
1012
                    {
1013
                        token = new AuthToken("Public");
1014
                    }
1015
                    InputStream data = cs.get(token, id);
1016
                    IOUtils.copyLarge(data, response.getOutputStream());
1017
                }
1018
                catch(InvalidToken it)
1019
                {
1020
                    response.setStatus(500);
1021
                    serializeException(it, out); 
1022
                }
1023
                catch(ServiceFailure sf)
1024
                {
1025
                    response.setStatus(500);
1026
                    serializeException(sf, out); 
1027
                }
1028
                catch(NotAuthorized na)
1029
                {
1030
                    response.setStatus(500);
1031
                    serializeException(na, out); 
1032
                }
1033
                catch(NotFound nf)
1034
                {
1035
                    response.setStatus(500);
1036
                    serializeException(nf, out); 
1037
                }
1038
                catch(NotImplemented ni)
1039
                {
1040
                    response.setStatus(500);
1041
                    serializeException(ni, out); 
1042
                }
1043
                catch(Exception e)
1044
                {
1045
                    response.setStatus(500);
1046
                    System.out.println("Error with Crud.get().  " +
1047
                            "If this is an 'Exception producing data' error, " +
1048
                            "go to CrudService.get() for better debugging.  " +
1049
                            "Here's the error: " + e.getMessage());
1050
                    e.printStackTrace();
1051
                    ServiceFailure sf = new ServiceFailure("1030", 
1052
                            "IO Error in ResourceHandler.getObject: " + e.getMessage());
1053
                    serializeException(sf, out); 
1054
                }
1055
            }
1056
            else
1057
            { //call listObjects with specified params
1058
                Date startTime = null;
1059
                Date endTime = null;
1060
                ObjectFormat objectFormat = null;
1061
                boolean replicaStatus = false;
1062
                int start = 0;
1063
                //TODO: make the max count into a const
1064
                int count = 1000;
1065
                Enumeration paramlist = request.getParameterNames();
1066
                while (paramlist.hasMoreElements()) 
1067
                { //parse the params and make the crud call
1068
                    String name = (String) paramlist.nextElement();
1069
                    String[] value = (String[])request.getParameterValues(name);
1070
                    /*for(int i=0; i<value.length; i++)
1071
                    {
1072
                        System.out.println("name: " + name + " value: " + value[i]);
1073
                    }*/
1074
                    if(name.equals("startTime") && value != null)
1075
                    {
1076
                        try
1077
                        {
1078
                          //startTime = dateFormat.parse(value[0]);
1079
                            startTime = parseDateAndConvertToGMT(value[0]);
1080
                        }
1081
                        catch(Exception e)
1082
                        {  //if we can't parse it, just don't use the startTime param
1083
                            System.out.println("Could not parse startTime: " + value[0]);
1084
                            startTime = null;
1085
                        }
1086
                    }
1087
                    else if(name.equals("endTime") && value != null)
1088
                    {
1089
                        try
1090
                        {
1091
                          //endTime = dateFormat.parse(value[0]);
1092
                            endTime = parseDateAndConvertToGMT(value[0]);
1093
                        }
1094
                        catch(Exception e)
1095
                        {  //if we can't parse it, just don't use the endTime param
1096
                            System.out.println("Could not parse endTime: " + value[0]);
1097
                            endTime = null;
1098
                        }
1099
                    }
1100
                    else if(name.equals("objectFormat") && value != null)
1101
                    {
1102
                        objectFormat = ObjectFormat.convert(value[0]);
1103
                    }
1104
                    else if(name.equals("replicaStatus") && value != null)
1105
                    {
1106
                        if(value != null && 
1107
                           value.length > 0 && 
1108
                           (value[0].equals("true") || value[0].equals("TRUE") || value[0].equals("YES")))
1109
                        {
1110
                            replicaStatus = true;
1111
                        }
1112
                    }
1113
                    else if(name.equals("start") && value != null)
1114
                    {
1115
                        start = new Integer(value[0]).intValue();
1116
                    }
1117
                    else if(name.equals("count") && value != null)
1118
                    {
1119
                        count = new Integer(value[0]).intValue();
1120
                    }
1121
                }
1122
                //make the crud call
1123
                System.out.println("token: " + token + " startTime: " + startTime +
1124
                        " endtime: " + endTime + " objectFormat: " + 
1125
                        objectFormat + " replicaStatus: " + replicaStatus + 
1126
                        " start: " + start + " count: " + count);
1127
               
1128
                ObjectList ol = cs.listObjects(token, startTime, endTime, 
1129
                        objectFormat, replicaStatus, start, count);
1130
                
1131
                StringReader sr = new StringReader(ol.toString());                
1132
                out = response.getOutputStream();  
1133
                response.setStatus(200);
1134
                response.setContentType("text/xml");
1135
                // Serialize and write it to the output stream
1136
                
1137
                try {
1138
                    serializeServiceType(ObjectList.class, ol, out);
1139
                } catch (JiBXException e) {
1140
                    throw new ServiceFailure("1190", "Failed to serialize ObjectList: " + e.getMessage());
1141
                }
1142
            }
1143
        } catch (BaseException e) {
1144
                response.setStatus(500);
1145
                serializeException(e, out);
1146
        } catch (IOException e) {
1147
            e.printStackTrace();
1148
            response.setStatus(500);
1149
            ServiceFailure sf = new ServiceFailure("1030", 
1150
                    "IO Error in ResourceHandler.getObject: " + e.getMessage());
1151
            serializeException(sf, out); 
1152
        } catch(NumberFormatException ne) {
1153
            response.setStatus(500);
1154
            InvalidRequest ir = new InvalidRequest("1030", "Invalid format for parameter: " + ne.getMessage());
1155
            serializeException(ir, out);
1156
        } catch (Exception e) {
1157
            e.printStackTrace();
1158
            response.setStatus(500);
1159
            ServiceFailure sf = new ServiceFailure("1030", 
1160
                    "Exception " + e.getClass().getName() + " raised while handling listObjects request: " + 
1161
                    e.getMessage());
1162
            serializeException(sf, out);
1163
        }
1164
    }
1165
    
1166
    /**
1167
     * parse a date and return it in GMT if it ends with a 'Z'
1168
     * @param date
1169
     * @return
1170
     * @throws ParseException
1171
     */
1172
    private Date parseDateAndConvertToGMT(String date) throws ParseException
1173
    {
1174
        try
1175
        {   //the format we want
1176
            return dateFormat.parse(date);
1177
        }
1178
        catch(java.text.ParseException pe)
1179
        {   //try another legacy format
1180
            DateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'");
1181
            dateFormat2.setTimeZone(TimeZone.getTimeZone("GMT-0"));
1182
            return dateFormat2.parse(date);
1183
        }    
1184
    }
1185

    
1186
    /**
1187
     * Implements REST version of DataONE CRUD API --> getSystemMetadata
1188
     * @param guid ID of data object to be read
1189
     */
1190
    private void getSystemMetadataObject(String guid) {
1191
        CrudService cs = CrudService.getInstance();
1192
        cs.setParamsFromRequest(request);
1193
        AuthToken token = new AuthToken(sessionId);
1194
        OutputStream out = null;
1195
        try {
1196
            response.setContentType("text/xml");
1197
            response.setStatus(200);
1198
            out = response.getOutputStream();
1199
            Identifier id = new Identifier();
1200
            id.setValue(guid);
1201
            SystemMetadata sysmeta = cs.getSystemMetadata(token, id);
1202
            
1203
            // Serialize and write it to the output stream
1204
            try {
1205
                //TODO: look at the efficiency of this method.  The system metadata
1206
                //is read from metacat (in CrudService) as xml, then serialized
1207
                //to a SystemMetadat object, then returned here, then serizlized
1208
                //back to XML to be sent to the response.
1209
                serializeServiceType(SystemMetadata.class, sysmeta, out);
1210
            } catch (JiBXException e) {
1211
                throw new ServiceFailure("1190", "Failed to serialize SystemMetadata: " + e.getMessage());
1212
            }
1213
        } catch (BaseException e) {
1214
            response.setStatus(500);
1215
                serializeException(e, out);
1216
        } catch (IOException e) {
1217
            response.setStatus(500);
1218
            ServiceFailure sf = new ServiceFailure("1030", 
1219
                    "Error in ResourceHandler.getSystemMetadataObject: " + e.getMessage());
1220
            serializeException(sf, out);
1221
        } finally {
1222
            IOUtils.closeQuietly(out);
1223
        }
1224
    }
1225
    
1226
    /**
1227
     * serialize an object of type to out
1228
     * @param type the class of the object to serialize (i.e. SystemMetadata.class)
1229
     * @param object the object to serialize
1230
     * @param out the stream to serialize it to
1231
     * @throws JiBXException
1232
     */
1233
    private void serializeServiceType(Class type, Object object, OutputStream out)
1234
      throws JiBXException
1235
    {
1236
        IBindingFactory bfact = BindingDirectory.getFactory(type);
1237
        IMarshallingContext mctx = bfact.createMarshallingContext();
1238
        mctx.marshalDocument(object, "UTF-8", null, out);
1239
    }
1240
    
1241
    /**
1242
     * deserialize an object of type from is
1243
     * @param type the class of the object to serialize (i.e. SystemMetadata.class)
1244
     * @param is the stream to deserialize from
1245
     * @throws JiBXException
1246
     */
1247
    private Object deserializeServiceType(Class type, InputStream is)
1248
      throws JiBXException
1249
    {
1250
        IBindingFactory bfact = BindingDirectory.getFactory(type);
1251
        IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
1252
        Object o = (Object) uctx.unmarshalDocument(is, null);
1253
        return o;
1254
    }
1255
    
1256
    /**
1257
     * Earthgrid API > Query Service > Query Function : translates ecogrid query document to metacat query 
1258
     * then calls DBQuery > createResultDocument function and then again translate resultset to ecogrid resultset
1259
     * 
1260
     * NOTE:
1261
     *      This is the only method that uses EcoGrid classes for its implementation.  
1262
     *      It does so because it takes an EcoGrid Query as input, and outputs an
1263
     *      EcoGrid ResultSet document.  These documents are parsed by the auto-generated
1264
     *      EcoGrid classes from axis, and so we link to them here rather than re-inventing them.
1265
     *      This creates a circular dependency, because the Metacat classes are needed
1266
     *      to build the EcoGrid implementation, and the EcoGrid jars are needed to build this query()
1267
     *      method.  This circularity could be resolved by moving the EcoGrid classes
1268
     *      to Metacat directly.  As we transition away from EcoGrid SOAP methods in
1269
     *      favor of these REST interfaces, this circular dependency can be eliminated.
1270
     *        
1271
     * @throws Exception
1272
     */
1273
    private void query() throws Exception {
1274
        /*  This block commented out because of the EcoGrid circular dependency.
1275
         *  For now, query will not be supported until the circularity can be
1276
         *  resolved, probably by moving the ecogrid query syntax transformers
1277
         *  directly into the Metacat codebase.  MBJ 2010-02-03
1278
         
1279
        try {
1280
            EcogridQueryParser parser = new EcogridQueryParser(request
1281
                    .getReader());
1282
            parser.parseXML();
1283
            QueryType queryType = parser.getEcogridQuery();
1284
            EcogridJavaToMetacatJavaQueryTransformer queryTransformer = 
1285
                new EcogridJavaToMetacatJavaQueryTransformer();
1286
            QuerySpecification metacatQuery = queryTransformer
1287
                    .transform(queryType);
1288

    
1289
            DBQuery metacat = new DBQuery();
1290

    
1291
            boolean useXMLIndex = (new Boolean(PropertyService
1292
                    .getProperty("database.usexmlindex"))).booleanValue();
1293
            String xmlquery = "query"; // we don't care the query in resultset,
1294
            // the query can be anything
1295
            PrintWriter out = null; // we don't want metacat result, so set out null
1296

    
1297
            // parameter: queryspecification, user, group, usingIndexOrNot
1298
            StringBuffer result = metacat.createResultDocument(xmlquery,
1299
                    metacatQuery, out, username, groupNames, useXMLIndex);
1300

    
1301
            // create result set transfer       
1302
            String saxparser = PropertyService.getProperty("xml.saxparser");
1303
            MetacatResultsetParser metacatResultsetParser = new MetacatResultsetParser(
1304
                    new StringReader(result.toString()), saxparser, queryType
1305
                            .getNamespace().get_value());
1306
            ResultsetType records = metacatResultsetParser.getEcogridResult();
1307

    
1308
            System.out
1309
                    .println(EcogridResultsetTransformer.toXMLString(records));
1310
            response.setContentType("text/xml");
1311
            out = response.getWriter();
1312
            out.print(EcogridResultsetTransformer.toXMLString(records));
1313

    
1314
        } catch (Exception e) {
1315
            e.printStackTrace();
1316
        }*/
1317
        response.setContentType("text/xml");
1318
        response.setStatus(501);
1319
        PrintWriter out = response.getWriter();
1320
        out.print("<error>Query operation not yet supported by Metacat.</error>");
1321
        out.close();
1322
    }
1323
    
1324
    private String streamToString(InputStream is)
1325
    throws IOException
1326
    {
1327
        return IOUtil.toString(is);
1328
    }
1329

    
1330
    private InputStream stringToStream(String s)
1331
    throws IOException
1332
    {
1333
        ByteArrayInputStream bais = new ByteArrayInputStream(s.getBytes(MetaCatServlet.DEFAULT_ENCODING));
1334
        return bais;
1335
    }
1336
    
1337
    /**
1338
     * process a mime multipart message
1339
     * @param is
1340
     * @return
1341
     */
1342
    /*private Hashtable processMMP(InputStream is)
1343
      throws IOException
1344
    {
1345
        //TODO: verify that this is how the RFC for MMP should work
1346
        //SORTAHACK: Since mmp seems to have a bug where large object parts get truncated,
1347
        //parse the stream here.  This has the disavantage of putting the
1348
        //stream into memory.
1349
        InputStream object = null;
1350
        InputStream sysmeta = null;
1351
        String s = IOUtils.toString(is);
1352
        System.out.println("mime: " + s);
1353
        //figure out what the boundary marker is
1354
        String searchString = "boundary=";
1355
        int searchStringIndex = s.indexOf(searchString);
1356
        String boundary = s.substring(searchStringIndex + searchString.length() + 1, 
1357
                s.indexOf("\"", searchStringIndex + searchString.length() + 1));
1358
        boundary = "--" + boundary;
1359
        //System.out.println("boundary is " + boundary);
1360
        
1361
        //find the system metadata
1362
        searchString = "Content-Disposition: attachment; filename=systemmetadata";
1363
        searchStringIndex = s.indexOf(searchString);
1364
        String sm = s.substring(searchStringIndex +
1365
                searchString.length() + 2, 
1366
                s.indexOf(boundary, searchStringIndex));
1367
        sysmeta = new ByteArrayInputStream(sm.getBytes());
1368
        
1369
        //find the object
1370
        searchString = "Content-Disposition: attachment; filename=object";
1371
        searchStringIndex = s.indexOf(searchString);
1372
        String o = s.substring(searchStringIndex +
1373
                searchString.length() + 2, 
1374
                s.indexOf(boundary, searchStringIndex));
1375
        object = new ByteArrayInputStream(o.getBytes());
1376
        
1377
        Hashtable h = new Hashtable();
1378
        h.put("object", object);
1379
        h.put("systemmetadata", sysmeta);
1380
                
1381
        //System.out.println("o: \"" + o + "\"");
1382
        //System.out.println("sm: \"" + sm + "\"");
1383
        return h;
1384
    }
1385
    */
1386
    
1387
    protected static String[] findBoundaryString(InputStream is)
1388
        throws IOException
1389
    {
1390
        String[] endResult = new String[2];
1391
        String boundary = "";
1392
        String searchString = "boundary=";
1393
        boolean doneWithCurrentArray = false;
1394
        byte[] b = new byte[1024];
1395
        int numbytes = is.read(b, 0, 1024);
1396
        while(numbytes != -1)
1397
        {
1398
            String s = new String(b, 0, numbytes);
1399
            
1400
            int[] result = StreamUtil.lookForMatch(searchString, s);
1401
            int searchStringIndex = s.indexOf(searchString);
1402
            if(s.indexOf("\"", searchStringIndex + searchString.length() + 1) == -1)
1403
            { //the end of the boundary is in the next byte array
1404
                boundary = s.substring(searchStringIndex + searchString.length() + 1, s.length());
1405
            }
1406
            else if(!boundary.startsWith("--"))
1407
            { //we can read the whole boundary from this byte array
1408
                boundary = s.substring(searchStringIndex + searchString.length() + 1, 
1409
                    s.indexOf("\"", searchStringIndex + searchString.length() + 1));
1410
                boundary = "--" + boundary;
1411
                endResult[0] = boundary;
1412
                endResult[1] = s.substring(s.indexOf("\"", searchStringIndex + searchString.length() + 1) + 1,
1413
                        s.length());
1414
                break;
1415
            }
1416
            else
1417
            { //we're now reading the 2nd byte array to get the rest of the boundary
1418
                searchString = "\"";
1419
                searchStringIndex = s.indexOf(searchString);
1420
                boundary += s.substring(0, searchStringIndex);
1421
                boundary = "--" + boundary;
1422
                endResult[0] = boundary;
1423
                endResult[1] = s.substring(s.indexOf("\"", searchStringIndex + searchString.length() + 1) + 1,
1424
                        s.length());
1425
                break;
1426
            }
1427
        }
1428
        System.out.println("boundary is: " + boundary);
1429
        return endResult;
1430
    }
1431
    
1432
    protected String writeMMPPartToFile(String beginSearch, 
1433
            InputStream is, String boundary, String searchString, File f)
1434
        throws IOException
1435
    {
1436
        Logger logMetacat = Logger.getLogger(ResourceHandler.class);
1437
        logMetacat.info("writing MMP parts");
1438
        //String s = beginSearch;
1439
        String s = null;
1440
        FileOutputStream fos = new FileOutputStream(f);
1441
        int numread = 0;
1442
        byte[] b = new byte[1024];
1443
        String writeString = "";
1444
        
1445
        if(s == null)
1446
        {   //starting with the first part of the stream 
1447
            numread = is.read(b, 0, 1024);
1448
            s = new String(b, 0, numread);
1449
        }
1450
        
1451
        if(beginSearch != null)
1452
        {
1453
            s = beginSearch + s;
1454
        }
1455
        
1456
        boolean useCurrentS = true;
1457
        boolean searchForBoundary = false;
1458
        String seekString = searchString;
1459
        
1460
        while(numread != -1)
1461
        {
1462
            logMetacat.info("////////////////////////iterating");
1463
            logMetacat.info("searchForBoundary: " + searchForBoundary);
1464
            logMetacat.info("useCurrentS: " + useCurrentS);
1465
            logMetacat.info("seekString: " + seekString);
1466
            logMetacat.info("in string: " + s);
1467
            if(searchForBoundary)
1468
            {
1469
                seekString = boundary;
1470
            }
1471
            else
1472
            {
1473
                seekString = searchString;
1474
            }
1475
            
1476
            int[] result = StreamUtil.lookForMatch(seekString, s);
1477
            if(!useCurrentS)
1478
            {
1479
                numread = is.read(b, 0, 1024);
1480
                if(numread != -1)
1481
                {
1482
                    s = new String(b, 0, numread);
1483
                }
1484
                else
1485
                {
1486
                    break;
1487
                }
1488
            }
1489
            
1490
            logMetacat.info("2seekString: " + seekString);
1491
            logMetacat.info("2in string: " + s);
1492
            
1493
            if(result[0] >= 0 && result[1] == seekString.length())
1494
            {
1495
                //searchString is full in s
1496
                logMetacat.info("seekstring is fully in s");
1497
                if(!searchForBoundary)
1498
                {   //we're looking for searchString and we found it
1499
                    //chop off the searchString itself and start writing
1500
                    //until we find boundary
1501
                    s = s.substring(result[0] + result[1], s.length());
1502
                    if(s.length() > 0)
1503
                    {
1504
                        useCurrentS = true;
1505
                    }
1506
                    else
1507
                    {
1508
                        useCurrentS = false;
1509
                    }
1510
                    searchForBoundary = true;
1511
                }
1512
                else
1513
                {   //we're writing, but we found the boundary in this chunk
1514
                    
1515
                    writeString = s.substring(0, result[0]);
1516
                    //System.out.println("writing1: " + writeString);
1517
                    fos.write(writeString.getBytes(MetaCatServlet.DEFAULT_ENCODING));
1518
                    //we're done.  break and return;
1519
                    return s.substring(result[0] + result[1], s.length());
1520
                }
1521
            }
1522
            else if(result[0] > 0 && result[1] != seekString.length())
1523
            {
1524
                logMetacat.info("seekstring is partially in s");
1525
                //seekString is partially in s
1526
                //more specifically, the beginning of seekString is at the end
1527
                //of s
1528
                
1529
                //get the next chunk right now, see if the beginning matches
1530
                numread = is.read(b, 0, 1024);
1531
                String s2 = new String(b, 0, numread);
1532
                s += s2;
1533
                useCurrentS = true;
1534
            }
1535
            else
1536
            {
1537
                logMetacat.info("seekstring is not in s");
1538
                //searchString is not in s 
1539
                if(searchForBoundary)
1540
                {
1541
                    //System.out.println("writing2: " + s);
1542
                    fos.write(s.getBytes(MetaCatServlet.DEFAULT_ENCODING));
1543
                }
1544
                numread = is.read(b, 0, 1024);
1545
                if(numread != -1)
1546
                {
1547
                    s = new String(b, 0, numread);
1548
                }
1549
                else
1550
                {
1551
                    break;
1552
                }
1553
                useCurrentS = true;
1554
            }
1555
        }
1556
        return "";
1557
    }
1558
    
1559
    protected Hashtable<String, File> writeMMPPartsToFiles(InputStream is)
1560
        throws IOException
1561
    {
1562
        Logger logMetacat = Logger.getLogger(ResourceHandler.class);
1563
        logMetacat.info("Processing Mime Multipart");
1564
        String[] boundaryResults = findBoundaryString(is);
1565
        String boundary = boundaryResults[0];
1566
        String s = boundaryResults[1];
1567
        String[] searchStrings = {
1568
                "Content-Disposition: attachment; filename=systemmetadata\n\n",
1569
                "Content-Disposition: attachment; filename=object\n\n"};
1570
        
1571
        File[] fileArr = getMMPTempFiles();
1572
        Hashtable<String, File> h = new Hashtable<String, File>();
1573
        //System.out.println("==========================Looking for SM");
1574
        //System.out.println("writing sm to " + fileArr[0].getAbsolutePath());
1575
        logMetacat.info("writing mime system metadata to " + fileArr[0].getAbsolutePath());
1576
        s = writeMMPPartToFile(s.trim(), is, boundary, searchStrings[0], fileArr[0]);
1577
        logMetacat.info("writeMMPPartToFile returned '" + s.trim() + "' after processing the system metadata");
1578
        //System.out.println("==========================Looking for Object");
1579
        //System.out.println("writing obj to " + fileArr[1].getAbsolutePath());
1580
        logMetacat.info("writing mime object to " + fileArr[1].getAbsolutePath());
1581
        writeMMPPartToFile(s.trim(), is, boundary, searchStrings[1], fileArr[1]);
1582
        h.put("sysmeta", fileArr[0]);
1583
        h.put("object", fileArr[1]);
1584
        return h;
1585
    }
1586
    
1587
    private static File[] getMMPTempFiles()
1588
        throws IOException
1589
    {
1590
        Logger logMetacat = Logger.getLogger(ResourceHandler.class);
1591
        File tmpDir;
1592
        try
1593
        {
1594
            tmpDir = new File(PropertyService.getProperty("application.tempDir"));
1595
        }
1596
        catch(PropertyNotFoundException pnfe)
1597
        {
1598
            logMetacat.error("ResourceHandler.writeMMPPartstoFiles: " +
1599
                    "application.tmpDir not found.  Using /tmp instead.");
1600
            tmpDir = new File("/tmp");
1601
        }
1602
        long datetimetag = new Date().getTime();
1603
        File smFile = new File(tmpDir, "sm." + datetimetag + ".tmp");
1604
        File objFile = new File(tmpDir, "obj." + datetimetag + ".tmp");
1605
        File[] fileArr = {smFile, objFile};
1606
        return fileArr;
1607
    }
1608
    
1609
    /**
1610
     * return a vector where the first element is a string that represents the system
1611
     * metadata and the 2nd element is an InputStream that is the object
1612
     */
1613
    protected Hashtable<String, File> processMMP(final InputStream is)
1614
      throws IOException
1615
    {
1616
        return writeMMPPartsToFiles(is);
1617
    }
1618
    
1619
    /**
1620
     * Earthgrid API > Put Service >Put Function : calls MetacatHandler > handleInsertOrUpdateAction 
1621
     * 
1622
     * @param guid ID of data object to be inserted or updated
1623
     * @throws IOException
1624
     */
1625
    private void putObject(String guid, String action) {
1626
        logMetacat.debug("Entering putObject: " + guid + "/" + action);
1627
        OutputStream out = null;
1628
        Hashtable<String, File> parts = null;
1629
        try {
1630
            out = response.getOutputStream();
1631
            response.setStatus(200);
1632
            response.setContentType("text/xml");
1633
        } catch (IOException e1) {
1634
            logMetacat.error("Could not get the output stream for writing in putObject");
1635
        }
1636
        try {
1637
            
1638
            // Read the incoming data from its Mime Multipart encoding
1639
            logMetacat.debug("Disassembling MIME multipart form");
1640
            InputStream object = null;
1641
            InputStream sysmeta = null;
1642
            
1643
            try
1644
            {
1645
                //String req = IOUtils.toString(request.getInputStream());
1646
                //System.out.println("request: " + req);
1647
                //InputStream reqStr = IOUtils.toInputStream(req);
1648
                InputStream reqStr = request.getInputStream();
1649
                parts = processMMP(reqStr);
1650
                object = new FileInputStream(parts.get("object"));
1651
                sysmeta = new FileInputStream(parts.get("sysmeta"));
1652
                
1653
                /*String obj = IOUtils.toString(object);
1654
                String sm = IOUtils.toString(sysmeta);
1655
                System.out.println("object: " + obj);
1656
                System.out.println("sm: " + sm);
1657
                object = IOUtils.toInputStream(obj);
1658
                sysmeta = IOUtils.toInputStream(sm);*/
1659
                
1660
            }
1661
            catch(IOException ioe)
1662
            {
1663
                throw new ServiceFailure("1202", 
1664
                        "IOException when processing Mime Multipart: " + ioe.getMessage());
1665
            }
1666
            
1667
            if ( action.equals(FUNCTION_NAME_INSERT)) { //handle inserts
1668

    
1669
                // Check if the objectId exists
1670
                IdentifierManager im = IdentifierManager.getInstance();
1671
                if (im.identifierExists(guid)) {
1672
                    throw new IdentifierNotUnique("1000", "Identifier is already in use: " + guid);
1673
                }
1674

    
1675
                logMetacat.debug("Commence creation...");
1676
                IBindingFactory bfact =
1677
                    BindingDirectory.getFactory(SystemMetadata.class);
1678
                IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
1679
                SystemMetadata m = (SystemMetadata) uctx.unmarshalDocument(sysmeta, null);
1680

    
1681
                CrudService cs = CrudService.getInstance();
1682
                AuthToken token = new AuthToken(sessionId); 
1683
                cs.setParamsFromRequest(request);
1684
                Identifier id = new Identifier();
1685
                id.setValue(guid);
1686
                System.out.println("creating object with guid " + id.getValue());
1687
                Identifier rId = cs.create(token, id, object, m);
1688
                serializeServiceType(Identifier.class, rId, out);
1689
                
1690
            } else if (action.equals(FUNCTION_NAME_UPDATE)) { //handle updates
1691
                IdentifierManager im = IdentifierManager.getInstance();
1692
                CrudService cs = CrudService.getInstance();
1693
                Identifier obsoletedGuid = new Identifier();
1694
                Identifier id = new Identifier();
1695
                id.setValue(guid);
1696
                AuthToken token = new AuthToken(sessionId);
1697
                
1698
                //do some checks
1699
                if(params.get("obsoletedGuid") == null)
1700
                {
1701
                    throw new InvalidRequest("1202", "obsoletedGuid must be contained in the request parameters.");
1702
                }
1703
                //get the obsoletedGuid
1704
                String[] obsGuidS = params.get("obsoletedGuid");
1705
                obsoletedGuid.setValue(obsGuidS[0]);
1706
                
1707
                if (!im.identifierExists(obsoletedGuid.getValue())) 
1708
                {
1709
                    throw new InvalidRequest("1202", "The guid you are trying to update does not exist.");
1710
                }
1711
                
1712
                
1713
                logMetacat.debug("Commence update...");
1714
                
1715
                //get the systemmetadata
1716
                IBindingFactory bfact =
1717
                        BindingDirectory.getFactory(SystemMetadata.class);
1718
                    IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
1719
                    SystemMetadata m = (SystemMetadata) uctx.unmarshalDocument(sysmeta, null);
1720
                
1721
                //do the update
1722
                try
1723
                {
1724
                    cs.setParamsFromRequest(request);
1725
                    Identifier rId = cs.update(token, id, object, obsoletedGuid, m);
1726
                    serializeServiceType(Identifier.class, rId, out);
1727
                }
1728
                catch(NotFound e)
1729
                {
1730
                    throw new InvalidRequest("1202", "The guid you are trying to update does not exist.");
1731
                }
1732
                
1733
            } else {
1734
                throw new InvalidRequest("1000", "Operation must be create or update.");
1735
            }
1736
            
1737
            //clean up the MMP files
1738
            parts.get("sysmeta").delete();
1739
            parts.get("object").delete();
1740
        } catch (NotAuthorized e) {
1741
            response.setStatus(500);
1742
            serializeException(e, out);
1743
        } catch (InvalidToken e) {
1744
            response.setStatus(500);
1745
            serializeException(e, out);
1746
        } catch (ServiceFailure e) {
1747
            response.setStatus(500);
1748
            serializeException(e, out);
1749
        } catch (IdentifierNotUnique e) {
1750
            response.setStatus(500);
1751
            serializeException(e, out);
1752
        } catch (UnsupportedType e) {
1753
            response.setStatus(500);
1754
            serializeException(e, out);
1755
        } catch (InsufficientResources e) {
1756
            response.setStatus(500);
1757
            serializeException(e, out);
1758
        } catch (InvalidSystemMetadata e) {
1759
            response.setStatus(500);
1760
            serializeException(e, out);
1761
        } catch (NotImplemented e) {
1762
            response.setStatus(500);
1763
            serializeException(e, out);
1764
        } catch (InvalidRequest e) {
1765
            response.setStatus(500);
1766
            serializeException(e, out);
1767
        } /*catch (MessagingException e) {
1768
            ServiceFailure sf = new ServiceFailure("1000", e.getMessage());
1769
            serializeException(sf, out);
1770
        } catch (IOException e) {
1771
            response.setStatus(500);
1772
            ServiceFailure sf = new ServiceFailure("1000", e.getMessage());
1773
            serializeException(sf, out);
1774
        }*/ catch (JiBXException e) {
1775
            response.setStatus(500);
1776
            e.printStackTrace(System.out);
1777
            InvalidSystemMetadata ism = new InvalidSystemMetadata("1080", e.getMessage());
1778
            serializeException(ism, out);
1779
        }
1780
        finally
1781
        {
1782
            if(parts != null)
1783
            {
1784
                parts.get("sysmeta").delete();
1785
                parts.get("object").delete();
1786
            }
1787
        }
1788
    }
1789

    
1790
    /**
1791
     * Handle delete 
1792
     * @param guid ID of data object to be deleted
1793
     * @throws IOException
1794
     */
1795
    private void deleteObject(String guid) throws IOException 
1796
    {
1797
        // Look up the localId for this global identifier
1798
        System.out.println("!!!!!!!!!!!!!!!!!deleting object " + guid);
1799
        IdentifierManager im = IdentifierManager.getInstance();
1800
        String localId = "";
1801
        OutputStream out = response.getOutputStream();
1802
        response.setStatus(200);
1803
        try {
1804
            localId = im.getLocalId(guid);
1805
        } catch (McdbDocNotFoundException e) {
1806
            NotFound nf = new NotFound("1340", "Document with guid " + guid + " not found.");
1807
            response.setStatus(404);
1808
            serializeException(nf, out);
1809
        }
1810
       
1811
        AuthToken token = new AuthToken(sessionId);
1812
        CrudService cs = CrudService.getInstance();
1813
        Identifier id = new Identifier();
1814
        id.setValue(guid);
1815
        try
1816
        {
1817
            System.out.println("Calling delete");
1818
            cs.delete(token, id);
1819
            serializeServiceType(Identifier.class, id, out);
1820
        } 
1821
        catch (NotAuthorized e) {
1822
            response.setStatus(500);
1823
            serializeException(e, out);
1824
        } catch (InvalidToken e) {
1825
            response.setStatus(500);
1826
            serializeException(e, out);
1827
        } catch (ServiceFailure e) {
1828
            response.setStatus(500);
1829
            serializeException(e, out);
1830
        } catch (NotImplemented e) {
1831
            response.setStatus(500);
1832
            serializeException(e, out);
1833
        } catch (InvalidRequest e) {
1834
            response.setStatus(500);
1835
            serializeException(e, out);
1836
        } catch(NotFound e) {
1837
            response.setStatus(500);
1838
            serializeException(e, out);
1839
        } catch(JiBXException e) {
1840
            response.setStatus(500);
1841
            serializeException(new ServiceFailure("1350", "JiBXException: " + e.getMessage()), out);
1842
        }
1843
        out.close();
1844
    }
1845
    
1846
    /**
1847
     * set the access perms on a document
1848
     * @throws IOException
1849
     */
1850
    private void setaccess() throws Exception
1851
    {
1852
        try
1853
        {
1854
            String guid = params.get("guid")[0];
1855
            Identifier id = new Identifier();
1856
            id.setValue(guid);
1857
            AuthToken token = new AuthToken(sessionId);
1858
            String principal = params.get("principal")[0];
1859
            String permission = params.get("permission")[0];
1860
            String permissionType = params.get("permissionType")[0];
1861
            String permissionOrder = params.get("permissionOrder")[0];
1862
            String setSystemMetadata = params.get("setsystemmetadata")[0];
1863
            boolean ssm = false;
1864
            if(setSystemMetadata.equals("true") || setSystemMetadata.equals("TRUE") ||
1865
                    setSystemMetadata.equals("yes"))
1866
            {
1867
                ssm = true;
1868
            }
1869
            CrudService cs = CrudService.getInstance();
1870
            //TODO: remove the setsystemmetadata param and set this so the systemmetadata always gets set
1871
            cs.setAccess(token, id, principal, permission, permissionType, permissionOrder, ssm);
1872
        }
1873
        catch(Exception e)
1874
        {
1875
            response.setStatus(500);
1876
            printError("Error setting access in ResourceHandler: " + e.getMessage(), response);
1877
            throw e;
1878
        }
1879
    }
1880

    
1881
    /**
1882
     * Earthgrid API > Authentication Service > Login Function : calls MetacatHandler > handleLoginAction
1883
     * 
1884
     * @throws IOException
1885
     */
1886
    private void login() throws IOException {
1887
        PrintWriter out = response.getWriter();
1888
        response.setStatus(200);
1889
        response.setContentType("text/xml");
1890
        handler.handleLoginAction(out, params, request, response);
1891
        out.close();
1892
    }
1893

    
1894
    /**
1895
     * Earthgrid API > Authentication Service > Logout Function : calls MetacatHandler > handleLogoutAction
1896
     * 
1897
     * @throws IOException
1898
     */
1899
    private void logout() throws IOException {
1900
        PrintWriter out = response.getWriter();
1901
        response.setStatus(200);
1902
        response.setContentType("text/xml");
1903
        handler.handleLogoutAction(out, params, request, response);
1904
        out.close();
1905
    }
1906

    
1907
    /**
1908
     * Prints xml response
1909
     * @param message Message to be displayed
1910
     * @param response Servlet response that xml message will be printed 
1911
     * */
1912
    private void printError(String message, HttpServletResponse response) {
1913
        try {
1914
            logMetacat.error("ResourceHandler: Printing error to servlet response: " + message);
1915
            PrintWriter out = response.getWriter();
1916
            response.setContentType("text/xml");
1917
            out.println("<?xml version=\"1.0\"?>");
1918
            out.println("<error>");
1919
            out.println(message);
1920
            out.println("</error>");
1921
            out.close();
1922
        } catch (IOException e) {
1923
            e.printStackTrace();
1924
        }
1925
    }
1926
    
1927
    /**
1928
     * serialize a D1 exception using jibx
1929
     * @param e
1930
     * @param out
1931
     */
1932
    private void serializeException(BaseException e, OutputStream out) {
1933
        // TODO: Use content negotiation to determine which return format to use
1934
        response.setContentType("text/xml");
1935
        response.setStatus(e.getCode());
1936
        
1937
        logMetacat.error("ResourceHandler: Serializing exception with code " + e.getCode() + ": " + e.getMessage());
1938
        e.printStackTrace();
1939
        
1940
        try {
1941
            IOUtils.write(e.serialize(BaseException.FMT_XML), out);
1942
        } catch (IOException e1) {
1943
            logMetacat.error("Error writing exception to stream. " 
1944
                    + e1.getMessage());
1945
        }
1946
    }
1947
    
1948
    /**
1949
     * create a new ServiceMethod declaration
1950
     * @param name
1951
     * @param rest
1952
     * @param implemented
1953
     * @return
1954
     */
1955
    private ServiceMethod getServiceMethod(String name, String rest, boolean implemented)
1956
    {
1957
        ServiceMethod sm = new ServiceMethod();
1958
        sm.setImplemented(implemented);
1959
        sm.setName(name);
1960
        sm.setRest(rest);
1961
        return sm;
1962
    }
1963

    
1964
}
(4-4/5)