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

    
145
 * </ul>
146
 * </li>
147
 * 
148
 * <li>
149
 * <h3>EarthGrid Identifier Service</h3><br/>
150
 * 
151
 * <ul>
152
 * <li><h3>isRegistered: </h3>		<br/>
153
 * <b>REST URL:</b>	<code>GET, [context-root]/identifier/[doc-id]?op=isregistered</code>   <br/>
154
 * <b>Returns:</b> message in XML format<br/><br/>
155
 * </li>
156

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

    
184
    /**HTTP Verb GET*/
185
    public static final byte GET = 1;
186
    /**HTTP Verb POST*/
187
    public static final byte POST = 2;
188
    /**HTTP Verb PUT*/
189
    public static final byte PUT = 3;
190
    /**HTTP Verb DELETE*/
191
    public static final byte DELETE = 4;
192

    
193
    /*
194
     * API Resources
195
     */
196
    private static final String RESOURCE_OBJECTS = "object";
197
    private static final String RESOURCE_META = "meta";
198
    private static final String RESOURCE_SESSION = "session";
199
    private static final String RESOURCE_IDENTIFIER = "identifier";
200
    private static final String RESOURCE_LOG = "log";
201

    
202
    /*
203
     * API Functions used as URL parameters
204
     */
205
    private static final String FUNCTION_KEYWORD = "op";
206
    private static final String FUNCTION_NAME_LOGIN = "login";
207
    private static final String FUNCTION_NAME_LOGOUT = "logout";
208
    private static final String FUNCTION_NAME_SET_ACCESS = "setaccess";
209
    private static final String FUNCTION_NAME_ISREGISTERED = "isregistered";
210
    private static final String FUNCTION_NAME_GETALLDOCS = "getalldocids";
211
    private static final String FUNCTION_NAME_GETNEXTREV = "getnextrevision";
212
    private static final String FUNCTION_NAME_GETNEXTOBJ = "getnextobject";
213
    private static final String FUNCTION_NAME_INSERT = "insert";
214
    private static final String FUNCTION_NAME_UPDATE = "update";
215
    private static final String FUNCTION_NAME_GENERATE_MISSING_SYSTEM_METADATA = "generatemissingsystemmetadata";
216

    
217
    private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
218
    
219
    private ServletContext servletContext;
220
    private Logger logMetacat;
221
    private MetacatHandler handler;
222
    private HttpServletRequest request;
223
    private HttpServletResponse response;
224
    private String username;
225
    private String password;
226
    private String sessionId;
227
    private String[] groupNames;
228

    
229
    private Hashtable<String, String[]> params;
230

    
231
    /**Initializes new instance by setting servlet context,request and response*/
232
    public ResourceHandler(ServletContext servletContext,
233
            HttpServletRequest request, HttpServletResponse response) {
234
        this.servletContext = servletContext;
235
        this.request = request;
236
        this.response = response;
237
    }
238

    
239
    /**
240
     * This function is called from REST APU servlet and handles each request to the servlet 
241
     * 
242
     * @param httpVerb (GET, POST, PUT or DELETE)
243
     */
244
    public void handle(byte httpVerb) {
245
        logMetacat = Logger.getLogger(ResourceHandler.class);
246
        try {
247
            String resource = request.getServletPath();
248
            String verb = "";
249
            
250
            System.out.println("handling verb " + httpVerb + " request with resource " + resource);
251
            boolean status = false;
252
            loadSessionData();
253

    
254
            if (resource != null) {
255
            	resource = request.getServletPath().substring(1);
256

    
257
            	params = new Hashtable<String, String[]>();
258
            	initParams();
259

    
260
            	Timer timer = new Timer();
261
            	handler = new MetacatHandler(timer);
262

    
263
            	if (resource.equals(RESOURCE_SESSION) && 
264
            			httpVerb == POST && 
265
            			params.get(FUNCTION_KEYWORD) != null) {
266
            		//System.out.println("function_keyword: " + params.get(FUNCTION_KEYWORD)[0]);
267
            		if (params.get(FUNCTION_KEYWORD)[0].equals(FUNCTION_NAME_LOGIN)) {
268
            			login();
269
            			status = true;
270
            		} else if (params.get(FUNCTION_KEYWORD)[0].equals(FUNCTION_NAME_LOGOUT)) {
271
            			logout();
272
            			status = true;
273
            		} else if (params.get(FUNCTION_KEYWORD)[0].equals(FUNCTION_NAME_SET_ACCESS)) {
274
            			setaccess();
275
            			status = true;
276
            			//System.out.println("done setting access");
277
            		}
278
            	} else if (resource.equals(RESOURCE_META)) {
279
            		if(params != null && params.get(FUNCTION_KEYWORD) != null &&
280
            				params.get(FUNCTION_KEYWORD)[0].equals(FUNCTION_NAME_GENERATE_MISSING_SYSTEM_METADATA))
281
            		{ //generate system metadata for any object that is
282
            			//a) not system metadata itself
283
            			//b) does not already have a system metadata id in the systemmetadata table
284
            			//c) not a BIN object (data)
285
            		    //TODO: check if we need this anymore.  Might be superceded
286
            		    //by MetacatPopulator
287
            			generateMissingSystemMetadata();
288
            			status = true;
289
            		}
290
            		else
291
            		{
292
            			String objectId = request.getPathInfo();
293
            			if (objectId != null && objectId.length() > 1) 
294
            			{
295
            				objectId = request.getPathInfo().substring(1);
296
            			}
297
            			getSystemMetadataObject(objectId);
298
            			status = true;
299
            		}
300

    
301
            	} else if (resource.equals(RESOURCE_OBJECTS)) {
302
            		logMetacat.debug("D1 Rest: Starting resource processing...");
303
            		loadSessionData();
304

    
305
            		String objectId = request.getPathInfo();
306
            		if (objectId != null && objectId.length() > 1) 
307
            		{
308
            			objectId = request.getPathInfo().substring(1);
309
            		}
310
            		else
311
            		{
312
            			objectId = null;
313
            		}
314

    
315
            		logMetacat.debug("verb:" + httpVerb);
316

    
317
            		if (httpVerb == GET) {
318
            			getObject(objectId);
319
            			status = true;
320
            		} else if (httpVerb == POST) {
321
            			putObject(objectId, FUNCTION_NAME_INSERT);
322
            			status = true;
323
            		} else if (httpVerb == PUT) {
324
            			putObject(objectId, FUNCTION_NAME_UPDATE);
325
            			status = true;
326
            		} else if (httpVerb == DELETE) {
327
            			deleteObject(objectId);
328
            			status = true;
329
            		}
330

    
331
            	} else if (resource.equals(RESOURCE_IDENTIFIER)) {
332

    
333
            		String identifierId = request.getPathInfo();
334
            		if (identifierId != null && identifierId.length() > 1)
335
            			identifierId = request.getPathInfo().substring(1); //trim the slash
336

    
337
            		if (httpVerb == GET) {
338
            			String op = params.get(FUNCTION_KEYWORD)[0];
339
            			if (op.equals(FUNCTION_NAME_ISREGISTERED)) {
340
            				isRegistered(identifierId);
341
            				status = true;
342
            			} else if (op.equals(FUNCTION_NAME_GETALLDOCS)) {
343
            				getAllDocIds();
344
            				status = true;
345
            			} else if (op.equals(FUNCTION_NAME_GETNEXTREV)) {
346
            				getNextRevision(identifierId);
347
            				status = true;
348
            			} else if (op.equals(FUNCTION_NAME_GETNEXTOBJ)) {
349
            				getNextObject();
350
            				status = true;
351
            			} 
352

    
353
            		} else if (httpVerb == PUT) {
354
            			//Earthgrid API > Identifier Service > addLSID Function 
355
            		    response.setStatus(501);
356
            			printError(
357
            					"This method is not supported by metacat.  To "
358
            					+ "add a new LSID, add a document to metacat.",
359
            					response);
360
            			status = true;
361
            		}
362

    
363
            	} else if (resource.equals(RESOURCE_LOG)) {
364
            		//handle log events
365
            		if(httpVerb == GET)
366
            		{
367
            			getLog();
368
            			status = true;
369
            		}
370
            		else
371
            		{
372
            		    //change to D1 spec for specifying which http methods are allowed for a resource
373
            		    response.setStatus(501);
374
            			printError("POST, PUT, DELETE is not supported for logs.", response);
375
            			status = true;
376
            		}
377

    
378
            	}
379

    
380
            	if (!status)
381
            	{
382
            	    response.setStatus(400);
383
            		printError("Incorrect parameters!", response);
384
            	}
385
            } else {
386
                response.setStatus(400);
387
            	printError("Incorrect resource!", response);
388
            }
389
        } catch (Exception e) {
390
        	logMetacat.error(e.getMessage());
391
        	e.printStackTrace();
392
        }
393
    }
394
    
395
    /**
396
     * get the logs from the CrudService based on passed params.  Available 
397
     * params are token, fromDate, toDate, event.  See 
398
     * http://mule1.dataone.org/ArchitectureDocs/mn_api_crud.html#MN_crud.getLogRecords
399
     * for more info
400
     */
401
    private void getLog()
402
    {
403
        OutputStream out = null;
404
        try
405
        {
406
            out = response.getOutputStream();
407
            response.setStatus(200);
408
            response.setContentType("text/xml");
409
            AuthToken token = new AuthToken(sessionId);
410
            String fromDateS = params.get("fromDate")[0];
411
            System.out.println("param fromDateS: " + fromDateS);
412
            Date fromDate = null;
413
            String toDateS = params.get("toDate")[0];
414
            System.out.println("param toDateS: " + toDateS);
415
            Date toDate = null;
416
            String eventS = params.get("event")[0];
417
            Event event = null;
418
            if(fromDateS != null)
419
            {
420
                //fromDate = dateFormat.parse(fromDateS);
421
                fromDate = parseDateAndConvertToGMT(fromDateS);
422
            }
423
            if(toDateS != null)
424
            {
425
                //toDate = dateFormat.parse(toDateS);
426
                toDate = parseDateAndConvertToGMT(toDateS);
427
            }
428
            if(eventS != null)
429
            {
430
                event = Event.convert(eventS);
431
            }
432
            System.out.println("fromDate: " + fromDate + " toDate: " + toDate);
433
            
434
            System.out.println("calling crudservice.getLogRecords");
435
            Log log = CrudService.getInstance().getLogRecords(token, fromDate, toDate, event);
436
            serializeServiceType(Log.class, log, out);
437
        }
438
        catch(Exception e)
439
        {
440
            String msg = "Could not get logs from CrudService: " + e.getMessage();
441
            response.setStatus(500);
442
            ServiceFailure sf = new ServiceFailure("1490", msg);
443
            logMetacat.error(msg);
444
            e.printStackTrace();
445
            serializeException(sf, out);
446
        }
447
    }
448
    
449
    /**
450
     *  copies request parameters to a hashtable which is given as argument to native metacathandler functions  
451
     */
452
    private void initParams() {
453

    
454
        String name = null;
455
        String[] value = null;
456
        Enumeration paramlist = request.getParameterNames();
457
        while (paramlist.hasMoreElements()) {
458
            name = (String) paramlist.nextElement();
459
            value = request.getParameterValues(name);
460
            params.put(name, value);
461
        }
462
    }
463

    
464
    /**
465
     * 
466
     * Load user details of metacat session from the request 
467
     * 
468
     */
469
    private void loadSessionData()
470
      throws Exception
471
    {
472
        SessionData sessionData = RequestUtil.getSessionData(request);
473
        try
474
        {
475
            username = null;
476
            password = null;
477
            groupNames = null;
478
            sessionId = null;
479
            
480
            boolean validSession = false;
481
            SessionService ss = SessionService.getInstance();
482
            System.out.println("sessionData: " + sessionData);
483
            if(sessionData == null)
484
            {
485
                username = "public";
486
                sessionId = "0";
487
                System.out.println("sessiondata is null.  Creating a public session.");
488
                return;
489
            }
490
            
491
            System.out.println("username: " + sessionData.getUserName());
492
            System.out.println("sessionid: " + sessionData.getId());
493
            //validate the session
494
            if(ss.isSessionRegistered(sessionData.getId()) && 
495
               !(sessionData.getUserName().equals("public") || sessionData.getId().equals("0")))
496
            {
497
                validSession = true;
498
            }
499
            
500
            if(validSession)
501
            {
502
                //if the session is valid, set these variables
503
                username = sessionData.getUserName();
504
                password = sessionData.getPassword();
505
                groupNames = sessionData.getGroupNames();
506
                sessionId = sessionData.getId();
507
                System.out.println("setting sessionid to " + sessionId);
508
                System.out.println("username: " + username);
509
            }
510
            
511
            //if the session is not valid or the username is null, set
512
            //username to public
513
            if (username == null) 
514
            {
515
                System.out.println("setting username to public.");
516
                username = "public";
517
            }
518
        }
519
        catch(Exception e)
520
        {
521
            e.printStackTrace();
522
            throw new Exception("Could not load the session data: " + e.getMessage());
523
        }
524
    }
525
    
526
    /**
527
     * generate missing system metadata for any science metadata objects
528
     * that don't already have it. https://trac.dataone.org/ticket/591
529
     * 
530
     * called with POST meta/?op=generatemissingsystemmetadata
531
     */
532
    private void generateMissingSystemMetadata()
533
    {
534
        AuthToken token = new AuthToken(sessionId);
535
        CrudService.getInstance().generateMissingSystemMetadata(token);
536
    }
537

    
538
    /**
539
     *  Earthgrid API > Identifier Service > isRegistered Function : 
540
     *  calls MetacatHandler > handleIdIsRegisteredAction
541
     * @param guid
542
     * @throws IOException
543
     */
544
    private void isRegistered(String guid) throws IOException
545
    {
546
        
547
        // Look up the localId for this guid
548
        IdentifierManager im = IdentifierManager.getInstance();
549
        String localId = "";
550
        try {
551
            localId = im.getLocalId(guid);
552
        } catch (McdbDocNotFoundException e) {
553
            // TODO: Need to return the proper DataONE exception
554
        }
555
        
556
        params.put("docid", new String[] { localId });
557
        PrintWriter out = response.getWriter();
558
        response.setStatus(200);
559
        response.setContentType("text/xml");
560
        handler.handleIdIsRegisteredAction(out, params, response);
561
        out.close();
562
    }
563

    
564
    /**
565
     * Earthgrid API > Identifier Service > getAllDocIds Function : 
566
     * calls MetacatHandler > handleGetAllDocidsAction
567
     * @throws IOException
568
     */
569
    private void getAllDocIds() throws IOException {
570
        PrintWriter out = response.getWriter();
571
        response.setStatus(200);
572
        response.setContentType("text/xml");
573
        handler.handleGetAllDocidsAction(out, params, response);
574
        out.close();
575
    }
576

    
577
    /**
578
     * Earthgrid API > Identifier Service > getNextRevision Function : 
579
     * calls MetacatHandler > handleGetRevisionAndDocTypeAction
580
     * @param guid
581
     * @throws IOException
582
     */
583
    private void getNextRevision(String guid) throws IOException 
584
    {
585
        params.put("docid", new String[] { guid });
586
        PrintWriter out = response.getWriter();
587
        response.setStatus(200);
588
        response.setContentType("text/xml");
589
        //handler.handleGetRevisionAndDocTypeAction(out, params);
590

    
591
        try {
592
            // Make sure there is a docid
593
            if (guid == null || guid.equals("")) {
594
                throw new Exception("User didn't specify docid!");
595
            }
596

    
597
            // Look up the localId for this guid
598
            IdentifierManager im = IdentifierManager.getInstance();
599
            String localId = "";
600
            try {
601
                localId = im.getLocalId(guid);
602
            } catch (McdbDocNotFoundException e) {
603
                // TODO: Need to return the proper DataONE exception
604
            }
605
           
606
            // Create a DBUtil object
607
            DBUtil dbutil = new DBUtil();
608
            // Get a rev and doctype
609
            String revAndDocType = dbutil
610
                    .getCurrentRevisionAndDocTypeForGivenDocument(localId);
611
            int revision = Integer.parseInt(revAndDocType.split(";")[0]) + 1;
612

    
613
            out.println("<?xml version=\"1.0\"?>");
614
            out.print("<next-revision>");
615
            out.print(revision);
616
            out.print("</next-revision>");
617

    
618
        } catch (Exception e) {
619
            // Handle exception
620
            response.setStatus(500);
621
            out.println("<?xml version=\"1.0\"?>");
622
            out.println("<error>");
623
            out.println(e.getMessage());
624
            out.println("</error>");
625
        }
626

    
627
        out.close();
628
    }
629

    
630
    /**
631
     * Earthgrid API > Identifier Service > getNextObject Function : 
632
     * calls MetacatHandler > handleGetMaxDocidAction
633
     * @throws IOException
634
     */
635
    private void getNextObject() throws IOException {
636
        PrintWriter out = response.getWriter();
637
        response.setStatus(200);
638
        response.setContentType("text/xml");
639
        handler.handleGetMaxDocidAction(out, params, response);
640
        out.close();
641
    }
642

    
643
    /**
644
     * Implements REST version of DataONE CRUD API --> get
645
     * @param guid ID of data object to be read
646
     */
647
    private void getObject(String guid) {
648
        CrudService cs = CrudService.getInstance();
649
        cs.setParamsFromRequest(request);
650
        AuthToken token = new AuthToken(sessionId);
651
        OutputStream out = null;
652
        try {
653
            out = response.getOutputStream();
654
            response.setStatus(200);
655
            response.setContentType("text/xml");
656
            if(guid != null)
657
            { //get a specific document                
658
                Identifier id = new Identifier();
659
                id.setValue(guid);
660
                try
661
                {
662
                    if(token == null)
663
                    {
664
                        token = new AuthToken("Public");
665
                    }
666
                    InputStream data = cs.get(token, id);
667
                    IOUtils.copyLarge(data, response.getOutputStream());
668
                }
669
                catch(InvalidToken it)
670
                {
671
                    response.setStatus(500);
672
                    serializeException(it, out); 
673
                }
674
                catch(ServiceFailure sf)
675
                {
676
                    response.setStatus(500);
677
                    serializeException(sf, out); 
678
                }
679
                catch(NotAuthorized na)
680
                {
681
                    response.setStatus(500);
682
                    serializeException(na, out); 
683
                }
684
                catch(NotFound nf)
685
                {
686
                    response.setStatus(500);
687
                    serializeException(nf, out); 
688
                }
689
                catch(NotImplemented ni)
690
                {
691
                    response.setStatus(500);
692
                    serializeException(ni, out); 
693
                }
694
                catch(Exception e)
695
                {
696
                    response.setStatus(500);
697
                    System.out.println("Error with Crud.get().  " +
698
                            "If this is an 'Exception producing data' error, " +
699
                            "go to CrudService.get() for better debugging.  " +
700
                            "Here's the error: " + e.getMessage());
701
                    e.printStackTrace();
702
                    ServiceFailure sf = new ServiceFailure("1030", 
703
                            "IO Error in ResourceHandler.getObject: " + e.getMessage());
704
                    serializeException(sf, out); 
705
                }
706
            }
707
            else
708
            { //call listObjects with specified params
709
                Date startTime = null;
710
                Date endTime = null;
711
                ObjectFormat objectFormat = null;
712
                boolean replicaStatus = false;
713
                int start = 0;
714
                //TODO: make the max count into a const
715
                int count = 1000;
716
                Enumeration paramlist = request.getParameterNames();
717
                while (paramlist.hasMoreElements()) 
718
                { //parse the params and make the crud call
719
                    String name = (String) paramlist.nextElement();
720
                    String[] value = (String[])request.getParameterValues(name);
721
                    /*for(int i=0; i<value.length; i++)
722
                    {
723
                        System.out.println("name: " + name + " value: " + value[i]);
724
                    }*/
725
                    if(name.equals("startTime") && value != null)
726
                    {
727
                        try
728
                        {
729
                          //startTime = dateFormat.parse(value[0]);
730
                            startTime = parseDateAndConvertToGMT(value[0]);
731
                        }
732
                        catch(Exception e)
733
                        {  //if we can't parse it, just don't use the startTime param
734
                            System.out.println("Could not parse startTime: " + value[0]);
735
                            startTime = null;
736
                        }
737
                    }
738
                    else if(name.equals("endTime") && value != null)
739
                    {
740
                        try
741
                        {
742
                          //endTime = dateFormat.parse(value[0]);
743
                            endTime = parseDateAndConvertToGMT(value[0]);
744
                        }
745
                        catch(Exception e)
746
                        {  //if we can't parse it, just don't use the endTime param
747
                            System.out.println("Could not parse endTime: " + value[0]);
748
                            endTime = null;
749
                        }
750
                    }
751
                    else if(name.equals("objectFormat") && value != null)
752
                    {
753
                        objectFormat = ObjectFormat.convert(value[0]);
754
                    }
755
                    else if(name.equals("replicaStatus") && value != null)
756
                    {
757
                        if(value != null && 
758
                           value.length > 0 && 
759
                           (value[0].equals("true") || value[0].equals("TRUE") || value[0].equals("YES")))
760
                        {
761
                            replicaStatus = true;
762
                        }
763
                    }
764
                    else if(name.equals("start") && value != null)
765
                    {
766
                        start = new Integer(value[0]).intValue();
767
                    }
768
                    else if(name.equals("count") && value != null)
769
                    {
770
                        count = new Integer(value[0]).intValue();
771
                    }
772
                }
773
                //make the crud call
774
                System.out.println("token: " + token + " startTime: " + startTime +
775
                        " endtime: " + endTime + " objectFormat: " + 
776
                        objectFormat + " replicaStatus: " + replicaStatus + 
777
                        " start: " + start + " count: " + count);
778
               
779
                ObjectList ol = cs.listObjects(token, startTime, endTime, 
780
                        objectFormat, replicaStatus, start, count);
781
                
782
                StringReader sr = new StringReader(ol.toString());                
783
                out = response.getOutputStream();  
784
                response.setStatus(200);
785
                response.setContentType("text/xml");
786
                // Serialize and write it to the output stream
787
                
788
                try {
789
                    serializeServiceType(ObjectList.class, ol, out);
790
                } catch (JiBXException e) {
791
                    throw new ServiceFailure("1190", "Failed to serialize ObjectList: " + e.getMessage());
792
                }
793
            }
794
        } catch (BaseException e) {
795
                response.setStatus(500);
796
                serializeException(e, out);
797
        } catch (IOException e) {
798
            e.printStackTrace();
799
            response.setStatus(500);
800
            ServiceFailure sf = new ServiceFailure("1030", 
801
                    "IO Error in ResourceHandler.getObject: " + e.getMessage());
802
            serializeException(sf, out); 
803
        } catch(NumberFormatException ne) {
804
            response.setStatus(500);
805
            InvalidRequest ir = new InvalidRequest("1030", "Invalid format for parameter: " + ne.getMessage());
806
            serializeException(ir, out);
807
        } catch (Exception e) {
808
            e.printStackTrace();
809
            response.setStatus(500);
810
            ServiceFailure sf = new ServiceFailure("1030", 
811
                    "Exception " + e.getClass().getName() + " raised while handling listObjects request: " + 
812
                    e.getMessage());
813
            serializeException(sf, out);
814
        }
815
    }
816
    
817
    /**
818
     * parse a date and return it in GMT if it ends with a 'Z'
819
     * @param date
820
     * @return
821
     * @throws ParseException
822
     */
823
    private Date parseDateAndConvertToGMT(String date) throws ParseException
824
    {
825
        try
826
        {   //the format we want
827
            return dateFormat.parse(date);
828
        }
829
        catch(java.text.ParseException pe)
830
        {   //try another legacy format
831
            DateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'");
832
            dateFormat2.setTimeZone(TimeZone.getTimeZone("GMT-0"));
833
            return dateFormat2.parse(date);
834
        }    
835
        
836
        /*System.out.println("Parsing date " + date);
837
        Date d = dateFormat.parse(date);
838
        
839
        if(date.endsWith("Z"))
840
        {
841
            Calendar lTime = Calendar.getInstance();
842
            lTime.setTime(d);
843
            Calendar zTime = Calendar.getInstance(TimeZone.getTimeZone("GMT-0"));
844
            zTime.set(Calendar.MONTH, lTime.get(Calendar.MONTH));
845
            zTime.set(Calendar.DATE, lTime.get(Calendar.DATE));
846
            zTime.set(Calendar.YEAR, lTime.get(Calendar.YEAR));
847
            zTime.set(Calendar.HOUR, lTime.get(Calendar.HOUR));
848
            zTime.set(Calendar.MINUTE, lTime.get(Calendar.MINUTE));
849
            zTime.set(Calendar.SECOND, lTime.get(Calendar.SECOND));
850
            
851
            System.out.println("date parsed to " + zTime.getTime());
852
            return zTime.getTime();
853
        }
854
        
855
        System.out.println("date parsed, but not converted. returned as " + d);
856
        return d;*/
857
    }
858

    
859
    /**
860
     * Implements REST version of DataONE CRUD API --> getSystemMetadata
861
     * @param guid ID of data object to be read
862
     */
863
    private void getSystemMetadataObject(String guid) {
864
        CrudService cs = CrudService.getInstance();
865
        cs.setParamsFromRequest(request);
866
        AuthToken token = new AuthToken(sessionId);
867
        OutputStream out = null;
868
        try {
869
            response.setContentType("text/xml");
870
            response.setStatus(200);
871
            out = response.getOutputStream();
872
            Identifier id = new Identifier();
873
            id.setValue(guid);
874
            SystemMetadata sysmeta = cs.getSystemMetadata(token, id);
875
            
876
            // Serialize and write it to the output stream
877
            try {
878
                //TODO: look at the efficiency of this method.  The system metadata
879
                //is read from metacat (in CrudService) as xml, then serialized
880
                //to a SystemMetadat object, then returned here, then serizlized
881
                //back to XML to be sent to the response.
882
                serializeServiceType(SystemMetadata.class, sysmeta, out);
883
            } catch (JiBXException e) {
884
                throw new ServiceFailure("1190", "Failed to serialize SystemMetadata: " + e.getMessage());
885
            }
886
        } catch (BaseException e) {
887
            response.setStatus(500);
888
                serializeException(e, out);
889
        } catch (IOException e) {
890
            response.setStatus(500);
891
            ServiceFailure sf = new ServiceFailure("1030", 
892
                    "Error in ResourceHandler.getSystemMetadataObject: " + e.getMessage());
893
            serializeException(sf, out);
894
        } finally {
895
            IOUtils.closeQuietly(out);
896
        }
897
    }
898
    
899
    /**
900
     * serialize an object of type to out
901
     * @param type the class of the object to serialize (i.e. SystemMetadata.class)
902
     * @param object the object to serialize
903
     * @param out the stream to serialize it to
904
     * @throws JiBXException
905
     */
906
    private void serializeServiceType(Class type, Object object, OutputStream out)
907
      throws JiBXException
908
    {
909
        IBindingFactory bfact = BindingDirectory.getFactory(type);
910
        IMarshallingContext mctx = bfact.createMarshallingContext();
911
        mctx.marshalDocument(object, "UTF-8", null, out);
912
    }
913
    
914
    /**
915
     * deserialize an object of type from is
916
     * @param type the class of the object to serialize (i.e. SystemMetadata.class)
917
     * @param is the stream to deserialize from
918
     * @throws JiBXException
919
     */
920
    private Object deserializeServiceType(Class type, InputStream is)
921
      throws JiBXException
922
    {
923
        IBindingFactory bfact = BindingDirectory.getFactory(type);
924
        IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
925
        Object o = (Object) uctx.unmarshalDocument(is, null);
926
        return o;
927
    }
928
    
929
    /**
930
     * Earthgrid API > Query Service > Query Function : translates ecogrid query document to metacat query 
931
     * then calls DBQuery > createResultDocument function and then again translate resultset to ecogrid resultset
932
     * 
933
     * NOTE:
934
     *      This is the only method that uses EcoGrid classes for its implementation.  
935
     *      It does so because it takes an EcoGrid Query as input, and outputs an
936
     *      EcoGrid ResultSet document.  These documents are parsed by the auto-generated
937
     *      EcoGrid classes from axis, and so we link to them here rather than re-inventing them.
938
     *      This creates a circular dependency, because the Metacat classes are needed
939
     *      to build the EcoGrid implementation, and the EcoGrid jars are needed to build this query()
940
     *      method.  This circularity could be resolved by moving the EcoGrid classes
941
     *      to Metacat directly.  As we transition away from EcoGrid SOAP methods in
942
     *      favor of these REST interfaces, this circular dependency can be eliminated.
943
     *        
944
     * @throws Exception
945
     */
946
    private void query() throws Exception {
947
        /*  This block commented out because of the EcoGrid circular dependency.
948
         *  For now, query will not be supported until the circularity can be
949
         *  resolved, probably by moving the ecogrid query syntax transformers
950
         *  directly into the Metacat codebase.  MBJ 2010-02-03
951
         
952
        try {
953
            EcogridQueryParser parser = new EcogridQueryParser(request
954
                    .getReader());
955
            parser.parseXML();
956
            QueryType queryType = parser.getEcogridQuery();
957
            EcogridJavaToMetacatJavaQueryTransformer queryTransformer = 
958
                new EcogridJavaToMetacatJavaQueryTransformer();
959
            QuerySpecification metacatQuery = queryTransformer
960
                    .transform(queryType);
961

    
962
            DBQuery metacat = new DBQuery();
963

    
964
            boolean useXMLIndex = (new Boolean(PropertyService
965
                    .getProperty("database.usexmlindex"))).booleanValue();
966
            String xmlquery = "query"; // we don't care the query in resultset,
967
            // the query can be anything
968
            PrintWriter out = null; // we don't want metacat result, so set out null
969

    
970
            // parameter: queryspecification, user, group, usingIndexOrNot
971
            StringBuffer result = metacat.createResultDocument(xmlquery,
972
                    metacatQuery, out, username, groupNames, useXMLIndex);
973

    
974
            // create result set transfer		
975
            String saxparser = PropertyService.getProperty("xml.saxparser");
976
            MetacatResultsetParser metacatResultsetParser = new MetacatResultsetParser(
977
                    new StringReader(result.toString()), saxparser, queryType
978
                            .getNamespace().get_value());
979
            ResultsetType records = metacatResultsetParser.getEcogridResult();
980

    
981
            System.out
982
                    .println(EcogridResultsetTransformer.toXMLString(records));
983
            response.setContentType("text/xml");
984
            out = response.getWriter();
985
            out.print(EcogridResultsetTransformer.toXMLString(records));
986

    
987
        } catch (Exception e) {
988
            e.printStackTrace();
989
        }*/
990
        response.setContentType("text/xml");
991
        response.setStatus(501);
992
        PrintWriter out = response.getWriter();
993
        out.print("<error>Query operation not yet supported by Metacat.</error>");
994
        out.close();
995
    }
996
    
997
    private String streamToString(InputStream is)
998
    throws IOException
999
    {
1000
        return IOUtil.toString(is);
1001
    }
1002

    
1003
    private InputStream stringToStream(String s)
1004
    throws IOException
1005
    {
1006
        ByteArrayInputStream bais = new ByteArrayInputStream(s.getBytes());
1007
        return bais;
1008
    }
1009
    
1010
    /**
1011
     * process a mime multipart message
1012
     * @param is
1013
     * @return
1014
     */
1015
    private Hashtable processMMP(InputStream is)
1016
      throws IOException
1017
    {
1018
        //TODO: verify that this is how the RFC for MMP should work
1019
        //SORTAHACK: Since mmp seems to have a bug where large object parts get truncated,
1020
        //parse the stream here.  This has the disavantage of putting the
1021
        //stream into memory.
1022
        InputStream object = null;
1023
        InputStream sysmeta = null;
1024
        String s = IOUtils.toString(is);
1025
        //System.out.println("mime: " + s);
1026
        //figure out what the boundary marker is
1027
        String searchString = "boundary=";
1028
        int searchStringIndex = s.indexOf(searchString);
1029
        String boundary = s.substring(searchStringIndex + searchString.length() + 1, 
1030
                s.indexOf("\"", searchStringIndex + searchString.length() + 1));
1031
        boundary = "--" + boundary;
1032
        //System.out.println("boundary is " + boundary);
1033
        
1034
        //find the system metadata
1035
        searchString = "Content-Disposition: attachment; filename=systemmetadata";
1036
        searchStringIndex = s.indexOf(searchString);
1037
        String sm = s.substring(searchStringIndex +
1038
                searchString.length() + 2, 
1039
                s.indexOf(boundary, searchStringIndex));
1040
        sysmeta = new ByteArrayInputStream(sm.getBytes());
1041
        
1042
        //find the object
1043
        searchString = "Content-Disposition: attachment; filename=object";
1044
        searchStringIndex = s.indexOf(searchString);
1045
        String o = s.substring(searchStringIndex +
1046
                searchString.length() + 2, 
1047
                s.indexOf(boundary, searchStringIndex));
1048
        object = new ByteArrayInputStream(o.getBytes());
1049
        
1050
        Hashtable h = new Hashtable();
1051
        h.put("object", object);
1052
        h.put("systemmetadata", sysmeta);
1053
                
1054
        //System.out.println("o: \"" + o + "\"");
1055
        //System.out.println("sm: \"" + sm + "\"");
1056
        return h;
1057
    }
1058
    
1059
    /*private Hashtable processMMP(InputStream is)
1060
      throws IOException
1061
    {
1062
        String[] searchStrings = {"boundary=", "Content-Disposition: attachment; filename=systemmetadata",
1063
                "Content-Disposition: attachment; filename=object"};
1064
        byte[] b = new byte[1024];
1065
        int numread = is.read(b, 0, 1024);
1066
        int ssi = 0;
1067
        while(numread != -1)
1068
        {
1069
            String s = new String(b, 0, numread);
1070
            int[] result = StreamUtil.lookForMatch(searchStrings[ssi], s);
1071
            
1072
        }
1073
    }*/
1074
    
1075
    /**
1076
     * Earthgrid API > Put Service >Put Function : calls MetacatHandler > handleInsertOrUpdateAction 
1077
     * 
1078
     * @param guid ID of data object to be inserted or updated
1079
     * @throws IOException
1080
     */
1081
    private void putObject(String guid, String action) {
1082
        logMetacat.debug("Entering putObject: " + guid + "/" + action);
1083
        OutputStream out = null;
1084
        try {
1085
            out = response.getOutputStream();
1086
            response.setStatus(200);
1087
            response.setContentType("text/xml");
1088
        } catch (IOException e1) {
1089
            logMetacat.error("Could not get the output stream for writing in putObject");
1090
        }
1091
        try {
1092
            
1093
            // Read the incoming data from its Mime Multipart encoding
1094
            logMetacat.debug("Disassembling MIME multipart form");
1095
            InputStream object = null;
1096
            InputStream sysmeta = null;
1097
            
1098
            Hashtable parts = processMMP(request.getInputStream());
1099
            object = (InputStream)parts.get("object");
1100
            
1101
            sysmeta = (InputStream)parts.get("systemmetadata");
1102
            
1103
            if ( action.equals(FUNCTION_NAME_INSERT)) { //handle inserts
1104

    
1105
                // Check if the objectId exists
1106
                IdentifierManager im = IdentifierManager.getInstance();
1107
                if (im.identifierExists(guid)) {
1108
                    throw new IdentifierNotUnique("1000", "Identifier is already in use: " + guid);
1109
                }
1110

    
1111
                logMetacat.debug("Commence creation...");
1112
                IBindingFactory bfact =
1113
                    BindingDirectory.getFactory(SystemMetadata.class);
1114
                IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
1115
                SystemMetadata m = (SystemMetadata) uctx.unmarshalDocument(sysmeta, null);
1116

    
1117
                CrudService cs = CrudService.getInstance();
1118
                AuthToken token = new AuthToken(sessionId); 
1119
                cs.setParamsFromRequest(request);
1120
                Identifier id = new Identifier();
1121
                id.setValue(guid);
1122
                cs.create(token, id, object, m);
1123
                
1124
            } else if (action.equals(FUNCTION_NAME_UPDATE)) { //handle updates
1125
                IdentifierManager im = IdentifierManager.getInstance();
1126
                CrudService cs = CrudService.getInstance();
1127
                Identifier obsoletedGuid = new Identifier();
1128
                Identifier id = new Identifier();
1129
                id.setValue(guid);
1130
                AuthToken token = new AuthToken(sessionId);
1131
                
1132
                //do some checks
1133
                if(params.get("obsoletedGuid") == null)
1134
                {
1135
                    throw new InvalidRequest("1202", "obsoletedGuid must be contained in the request parameters.");
1136
                }
1137
                //get the obsoletedGuid
1138
                String[] obsGuidS = params.get("obsoletedGuid");
1139
                obsoletedGuid.setValue(obsGuidS[0]);
1140
                
1141
                if (!im.identifierExists(obsoletedGuid.getValue())) 
1142
                {
1143
                    throw new InvalidRequest("1202", "The guid you are trying to update does not exist.");
1144
                }
1145
                
1146
                
1147
                logMetacat.debug("Commence update...");
1148
                
1149
                //get the systemmetadata
1150
                IBindingFactory bfact =
1151
                        BindingDirectory.getFactory(SystemMetadata.class);
1152
                    IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
1153
                    SystemMetadata m = (SystemMetadata) uctx.unmarshalDocument(sysmeta, null);
1154
                
1155
                //do the update
1156
                try
1157
                {
1158
                    cs.setParamsFromRequest(request);
1159
                    Identifier rId = cs.update(token, id, object, obsoletedGuid, m);
1160
                }
1161
                catch(NotFound e)
1162
                {
1163
                    throw new InvalidRequest("1202", "The guid you are trying to update does not exist.");
1164
                }
1165
                
1166
            } else {
1167
                throw new InvalidRequest("1000", "Operation must be create or update.");
1168
            }
1169
        } catch (NotAuthorized e) {
1170
            response.setStatus(500);
1171
            serializeException(e, out);
1172
        } catch (InvalidToken e) {
1173
            response.setStatus(500);
1174
            serializeException(e, out);
1175
        } catch (ServiceFailure e) {
1176
            response.setStatus(500);
1177
            serializeException(e, out);
1178
        } catch (IdentifierNotUnique e) {
1179
            response.setStatus(500);
1180
            serializeException(e, out);
1181
        } catch (UnsupportedType e) {
1182
            response.setStatus(500);
1183
            serializeException(e, out);
1184
        } catch (InsufficientResources e) {
1185
            response.setStatus(500);
1186
            serializeException(e, out);
1187
        } catch (InvalidSystemMetadata e) {
1188
            response.setStatus(500);
1189
            serializeException(e, out);
1190
        } catch (NotImplemented e) {
1191
            response.setStatus(500);
1192
            serializeException(e, out);
1193
        } catch (InvalidRequest e) {
1194
            response.setStatus(500);
1195
            serializeException(e, out);
1196
        } /*catch (MessagingException e) {
1197
            ServiceFailure sf = new ServiceFailure("1000", e.getMessage());
1198
            serializeException(sf, out);
1199
        }*/ catch (IOException e) {
1200
            response.setStatus(500);
1201
            ServiceFailure sf = new ServiceFailure("1000", e.getMessage());
1202
            serializeException(sf, out);
1203
        } catch (JiBXException e) {
1204
            response.setStatus(500);
1205
            e.printStackTrace(System.out);
1206
            InvalidSystemMetadata ism = new InvalidSystemMetadata("1080", e.getMessage());
1207
            serializeException(ism, out);
1208
        }
1209
    }
1210

    
1211
    /**
1212
     * Earthgrid API > Put Service > Delete Function : calls MetacatHandler > handleDeleteAction  
1213
     * 
1214
     * @param guid ID of data object to be deleted
1215
     * @throws IOException
1216
     */
1217
    private void deleteObject(String guid) throws IOException 
1218
    {
1219
        // Look up the localId for this global identifier
1220
        IdentifierManager im = IdentifierManager.getInstance();
1221
        String localId = "";
1222
        try {
1223
            localId = im.getLocalId(guid);
1224
        } catch (McdbDocNotFoundException e) {
1225
            // TODO: Need to return the proper DataONE exception
1226
        }
1227
        
1228
        params.put("docid", new String[] { localId });
1229
        PrintWriter out = response.getWriter();
1230
        response.setStatus(200);
1231
        response.setContentType("text/xml");
1232
        handler.handleDeleteAction(out, params, request, response, username,
1233
                groupNames);
1234
        out.close();
1235
    }
1236
    
1237
    /**
1238
     * set the access perms on a document
1239
     * @throws IOException
1240
     */
1241
    private void setaccess() throws Exception
1242
    {
1243
        try
1244
        {
1245
            String guid = params.get("guid")[0];
1246
            Identifier id = new Identifier();
1247
            id.setValue(guid);
1248
            AuthToken token = new AuthToken(sessionId);
1249
            String principal = params.get("principal")[0];
1250
            String permission = params.get("permission")[0];
1251
            String permissionType = params.get("permissionType")[0];
1252
            String permissionOrder = params.get("permissionOrder")[0];
1253
            String setSystemMetadata = params.get("setsystemmetadata")[0];
1254
            boolean ssm = false;
1255
            if(setSystemMetadata.equals("true") || setSystemMetadata.equals("TRUE") ||
1256
                    setSystemMetadata.equals("yes"))
1257
            {
1258
                ssm = true;
1259
            }
1260
            CrudService cs = CrudService.getInstance();
1261
            //TODO: remove the setsystemmetadata param and set this so the systemmetadata always gets set
1262
            cs.setAccess(token, id, principal, permission, permissionType, permissionOrder, ssm);
1263
        }
1264
        catch(Exception e)
1265
        {
1266
            response.setStatus(500);
1267
            printError("Error setting access in ResourceHandler: " + e.getMessage(), response);
1268
            throw e;
1269
        }
1270
    }
1271

    
1272
    /**
1273
     * Earthgrid API > Authentication Service > Login Function : calls MetacatHandler > handleLoginAction
1274
     * 
1275
     * @throws IOException
1276
     */
1277
    private void login() throws IOException {
1278
        PrintWriter out = response.getWriter();
1279
        response.setStatus(200);
1280
        response.setContentType("text/xml");
1281
        handler.handleLoginAction(out, params, request, response);
1282
        out.close();
1283
    }
1284

    
1285
    /**
1286
     * Earthgrid API > Authentication Service > Logout Function : calls MetacatHandler > handleLogoutAction
1287
     * 
1288
     * @throws IOException
1289
     */
1290
    private void logout() throws IOException {
1291
        PrintWriter out = response.getWriter();
1292
        response.setStatus(200);
1293
        response.setContentType("text/xml");
1294
        handler.handleLogoutAction(out, params, request, response);
1295
        out.close();
1296
    }
1297

    
1298
    /**
1299
     * Prints xml response
1300
     * @param message Message to be displayed
1301
     * @param response Servlet response that xml message will be printed 
1302
     * */
1303
    private void printError(String message, HttpServletResponse response) {
1304
        try {
1305
            logMetacat.error("ResourceHandler: Printing error to servlet response: " + message);
1306
            PrintWriter out = response.getWriter();
1307
            response.setContentType("text/xml");
1308
            out.println("<?xml version=\"1.0\"?>");
1309
            out.println("<error>");
1310
            out.println(message);
1311
            out.println("</error>");
1312
            out.close();
1313
        } catch (IOException e) {
1314
            e.printStackTrace();
1315
        }
1316
    }
1317
    
1318
    private void serializeException(BaseException e, OutputStream out) {
1319
        // TODO: Use content negotiation to determine which return format to use
1320
        response.setContentType("text/xml");
1321
        response.setStatus(e.getCode());
1322
        
1323
        logMetacat.error("ResourceHandler: Serializing exception with code " + e.getCode() + ": " + e.getMessage());
1324
        e.printStackTrace();
1325
        
1326
        try {
1327
            IOUtils.write(e.serialize(BaseException.FMT_XML), out);
1328
        } catch (IOException e1) {
1329
            logMetacat.error("Error writing exception to stream. " 
1330
                    + e1.getMessage());
1331
        }
1332
    }
1333

    
1334
}
(2-2/3)