Project

General

Profile

1 5211 jones
/**
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 5370 berkley
import java.io.*;
26
import java.util.*;
27 5211 jones
28 5319 jones
import javax.mail.BodyPart;
29
import javax.mail.MessagingException;
30
import javax.mail.internet.MimeMultipart;
31 5211 jones
import javax.servlet.ServletContext;
32
import javax.servlet.http.HttpServletRequest;
33
import javax.servlet.http.HttpServletResponse;
34 5370 berkley
import java.text.DateFormat;
35 5428 berkley
import java.text.ParseException;
36 5391 berkley
import java.text.ParsePosition;
37
import java.text.SimpleDateFormat;
38 5211 jones
39 5391 berkley
40 5390 berkley
import org.apache.commons.httpclient.util.DateParser;
41 5299 jones
import org.apache.commons.io.IOUtils;
42 5211 jones
import org.apache.log4j.Logger;
43 5629 berkley
import org.apache.maven.artifact.ant.shaded.IOUtil;
44 5299 jones
import org.dataone.service.exceptions.BaseException;
45 5319 jones
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 5299 jones
import org.dataone.service.exceptions.ServiceFailure;
53 5319 jones
import org.dataone.service.exceptions.UnsupportedType;
54 5353 berkley
import org.dataone.service.exceptions.NotFound;
55 5370 berkley
import org.dataone.service.types.*;
56 5320 jones
import org.jibx.runtime.BindingDirectory;
57
import org.jibx.runtime.IBindingFactory;
58 5332 jones
import org.jibx.runtime.IMarshallingContext;
59 5320 jones
import org.jibx.runtime.IUnmarshallingContext;
60
import org.jibx.runtime.JiBXException;
61 5211 jones
62
import edu.ucsb.nceas.metacat.DBUtil;
63 5282 jones
import edu.ucsb.nceas.metacat.IdentifierManager;
64
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
65 5211 jones
import edu.ucsb.nceas.metacat.MetacatHandler;
66 5425 berkley
import edu.ucsb.nceas.metacat.client.InsufficientKarmaException;
67 5299 jones
import edu.ucsb.nceas.metacat.dataone.CrudService;
68 5637 berkley
import edu.ucsb.nceas.metacat.properties.PropertyService;
69 5374 berkley
import edu.ucsb.nceas.metacat.service.SessionService;
70 5211 jones
import edu.ucsb.nceas.metacat.util.RequestUtil;
71
import edu.ucsb.nceas.metacat.util.SessionData;
72 5637 berkley
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
73
74 5629 berkley
import org.dataone.service.streaming.util.StreamUtil;
75 5636 berkley
76
import com.gc.iotools.stream.is.InputStreamFromOutputStream;
77 5211 jones
/**
78
 *
79
 * Implements Earthgrid REST API to Metacat <br/><br/>
80
 *
81
 * <ul>
82
 * <li>
83
 * <h3> EarthGrid Query Service</h3>
84
 * <ul><li>
85
 * <h3>Get & Authenticated Get:</h3>
86
 * is equal to Metacat's read action and returns a data file having
87
 * the specified <doc-id> in the resource path. For authenticated Get service, a session id must be provided
88
 * in the query string. <br/><br/>
89
 *
90 5657 berkley
 * <b>REST URL:</b> <code>GET, [context-root]/object/[doc-id]?sessionid=[sessionid] </code><br/>
91 5211 jones
 * <b>Returns:</b> data file <br/><br/>
92
 * </li>
93
 *
94
 * <li>
95
 * <h3>Query & Authenticated Query:</h3>
96
 * Metacat's equivalent is squery action but this function
97
 * receives a Earthgrid query document and returns Earthgrid resultset document by transforming those documents
98
 * to Metacat's equivalents by the means of Metacat Implementation in Earthgrid library. For authenticated Query service
99
 * a session id must be provided in the query string. See Earthgrid (a.k.a. Ecogrid) project for XSD files of
100
 * query and resultset documents<br/><br/>
101
 *
102 5657 berkley
 * <b>REST URL:</b> <code>POST, [context-root]/object?sessionid=[sessionid]</code>    <br/>
103 5211 jones
 * <b>POST Data:</b> Earthgrid query document , Content-type: <code>text/xml</code><br/>
104
 * <b>Returns:</b> Earthgrid resultset document<br/><br/>
105
 *
106
 * </li>
107
 * </ul>
108
 *
109
 * </li>
110
 *
111
 * <li>
112
 * <h3> EarthGrid Authentication Service</h3>
113
 * <ul><li>
114
 * <h3>Login: </h3>
115
 * Receives username and password parameters in POST data and
116
 * returns SessionId (in XML format) or failure message and uses MetacatHandler's handleLoginAction function<br/><br/>
117
 *
118
 * <b>REST URL:</b> <code>POST, [context-root]/session?op=login</code> <br/>
119
 * <b>POST Data:</b> username=[username]&password=[password], Content-type: <code>application/x-www-form-urlencoded</code>
120
 * <b>Returns:</b> sessionId in XML format<br/><br/>
121
 * </li>
122
 *
123
 * <li>
124
 * <h3>Logout: </h3>
125
 * Receives session Id parameters in querystring and returns xml message, calls
126
 * MetacatHandler's handleLogoutAction function<br/><br/>
127
 *
128 5657 berkley
 * <b>REST URL:</b> <code>GET, [context-root]/session?op=logout&sessionid=[sessionid]</code>   <br/>
129 5211 jones
 * <b>Returns:</b> message in XML format<br/><br/>
130
 * </li>
131
 * </ul>
132
 *
133
 * <li>
134
 * <h3>EarthGrid Put Service</h3>
135
 *
136
 * <ul>
137 5657 berkley
 * <li><h3>Update/Insert: </h3>
138 5211 jones
 * <br/>
139 5657 berkley
 * <b>REST URL:</b> <code>PUT, [context-root]/object/[doc-id]?op={update|insert}&sessionid=[sessionid]</code>   <br/>
140 5211 jones
 * <b>POST Data:</b> document object, Content-type: <code>text/xml</code><br/>
141
 * <b>Returns:</b> message in XML format<br/><br/>
142
 * </li>
143
 *
144 5657 berkley
 * <li><h3>Delete: </h3>
145 5211 jones
 * <br/>
146 5657 berkley
 * <b>REST URL:</b> <code>DELETE, [context-root]/object/[doc-id]?sessionid=[sessionid]</code>   <br/>
147 5211 jones
 * <b>Returns:</b> message in XML format<br/><br/>
148
 * </li>
149
150
 * </ul>
151
 * </li>
152
 *
153
 * <li>
154
 * <h3>EarthGrid Identifier Service</h3><br/>
155
 *
156
 * <ul>
157 5657 berkley
 * <li><h3>isRegistered: </h3>      <br/>
158
 * <b>REST URL:</b> <code>GET, [context-root]/identifier/[doc-id]?op=isregistered</code>   <br/>
159 5211 jones
 * <b>Returns:</b> message in XML format<br/><br/>
160
 * </li>
161
162 5657 berkley
 * <li><h3>getAllDocIds:</h3>       <br/>
163
 * <b>REST URL:</b> <code>GET, [context-root]/identifier?op=getalldocids</code>   <br/>
164 5211 jones
 * <b>Returns:</b> document id list in XML format<br/><br/>
165
 * </li>
166
 *
167
 * <li><h3>addLSID Function:</h3>
168 5657 berkley
 * Metacat does not support this function       <br/>
169
 * <b>REST URL:</b> <code>PUT, [context-root]/identifier/[doc-id]</code>   <br/>
170 5211 jones
 * <b>Returns:</b> error message in XML format<br/><br/>
171
 * </li>
172
 *
173 5657 berkley
 * <li><h3>getNextRevision:</h3>        <br/>
174
 * <b>REST URL:</b> <code>GET, [context-root]/identifier/[doc-id]?op=getnextrevision</code>   <br/>
175 5211 jones
 * <b>Returns:</b> message in XML format<br/><br/>
176
 * </li>
177
 *
178 5657 berkley
 * <li><h3>getNextObject:</h3>      <br/>
179
 * <b>REST URL:</b> <code>GET, [context-root]/identifier?op=getnextobject&scope=[scope]</code>   <br/>
180 5211 jones
 * <b>Returns:</b> message in XML format<br/><br/>
181
 * </li>
182
 *
183
 * </li>
184
 * </ul>
185
 *
186
 */
187
public class ResourceHandler {
188
189
    /**HTTP Verb GET*/
190
    public static final byte GET = 1;
191
    /**HTTP Verb POST*/
192
    public static final byte POST = 2;
193
    /**HTTP Verb PUT*/
194
    public static final byte PUT = 3;
195
    /**HTTP Verb DELETE*/
196
    public static final byte DELETE = 4;
197 5651 berkley
    /**HTTP Verb HEAD*/
198
    public static final byte HEAD = 5;
199 5211 jones
200
    /*
201
     * API Resources
202
     */
203 5224 jones
    private static final String RESOURCE_OBJECTS = "object";
204 5355 berkley
    private static final String RESOURCE_META = "meta";
205 5211 jones
    private static final String RESOURCE_SESSION = "session";
206
    private static final String RESOURCE_IDENTIFIER = "identifier";
207 5390 berkley
    private static final String RESOURCE_LOG = "log";
208 5644 berkley
    private static final String RESOURCE_CHECKSUM = "checksum";
209 5211 jones
210
    /*
211
     * API Functions used as URL parameters
212
     */
213
    private static final String FUNCTION_KEYWORD = "op";
214
    private static final String FUNCTION_NAME_LOGIN = "login";
215
    private static final String FUNCTION_NAME_LOGOUT = "logout";
216 5370 berkley
    private static final String FUNCTION_NAME_SET_ACCESS = "setaccess";
217 5211 jones
    private static final String FUNCTION_NAME_ISREGISTERED = "isregistered";
218
    private static final String FUNCTION_NAME_GETALLDOCS = "getalldocids";
219
    private static final String FUNCTION_NAME_GETNEXTREV = "getnextrevision";
220
    private static final String FUNCTION_NAME_GETNEXTOBJ = "getnextobject";
221
    private static final String FUNCTION_NAME_INSERT = "insert";
222
    private static final String FUNCTION_NAME_UPDATE = "update";
223 5374 berkley
    private static final String FUNCTION_NAME_GENERATE_MISSING_SYSTEM_METADATA = "generatemissingsystemmetadata";
224 5211 jones
225 5652 berkley
    private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
226 5414 berkley
227 5211 jones
    private ServletContext servletContext;
228
    private Logger logMetacat;
229
    private MetacatHandler handler;
230
    private HttpServletRequest request;
231
    private HttpServletResponse response;
232
    private String username;
233
    private String password;
234
    private String sessionId;
235
    private String[] groupNames;
236
237
    private Hashtable<String, String[]> params;
238
239
    /**Initializes new instance by setting servlet context,request and response*/
240
    public ResourceHandler(ServletContext servletContext,
241
            HttpServletRequest request, HttpServletResponse response) {
242
        this.servletContext = servletContext;
243
        this.request = request;
244
        this.response = response;
245
    }
246
247
    /**
248
     * This function is called from REST APU servlet and handles each request to the servlet
249
     *
250
     * @param httpVerb (GET, POST, PUT or DELETE)
251
     */
252
    public void handle(byte httpVerb) {
253
        logMetacat = Logger.getLogger(ResourceHandler.class);
254
        try {
255
            String resource = request.getServletPath();
256 5691 berkley
            //substring off the /d1/
257
            resource = resource.substring(resource.indexOf("d1/") + 3, resource.length());
258
            resource = resource.trim();
259 5355 berkley
            String verb = "";
260 5370 berkley
261 5691 berkley
            System.out.println("handling verb " + httpVerb + " request with resource '" + resource + "'");
262 5211 jones
            boolean status = false;
263 5424 berkley
            loadSessionData();
264 5211 jones
265
            if (resource != null) {
266 5691 berkley
                //resource = request.getServletPath().substring(1);
267 5211 jones
268 5657 berkley
                params = new Hashtable<String, String[]>();
269
                initParams();
270 5211 jones
271 5657 berkley
                Timer timer = new Timer();
272
                handler = new MetacatHandler(timer);
273 5211 jones
274 5657 berkley
                if (resource.equals(RESOURCE_SESSION) &&
275
                        httpVerb == POST &&
276
                        params.get(FUNCTION_KEYWORD) != null) {
277 5691 berkley
                    System.out.println("Using resource 'session'");
278 5657 berkley
                    //System.out.println("function_keyword: " + params.get(FUNCTION_KEYWORD)[0]);
279
                    if (params.get(FUNCTION_KEYWORD)[0].equals(FUNCTION_NAME_LOGIN)) {
280
                        login();
281
                        status = true;
282
                    } else if (params.get(FUNCTION_KEYWORD)[0].equals(FUNCTION_NAME_LOGOUT)) {
283
                        logout();
284
                        status = true;
285
                    } else if (params.get(FUNCTION_KEYWORD)[0].equals(FUNCTION_NAME_SET_ACCESS)) {
286
                        setaccess();
287
                        status = true;
288
                        //System.out.println("done setting access");
289
                    }
290
                } else if (resource.equals(RESOURCE_META)) {
291 5691 berkley
                    System.out.println("Using resource 'meta'");
292 5657 berkley
                    if(params != null && params.get(FUNCTION_KEYWORD) != null &&
293
                            params.get(FUNCTION_KEYWORD)[0].equals(FUNCTION_NAME_GENERATE_MISSING_SYSTEM_METADATA))
294
                    { //generate system metadata for any object that is
295
                        //a) not system metadata itself
296
                        //b) does not already have a system metadata id in the systemmetadata table
297
                        //c) not a BIN object (data)
298
                        //TODO: check if we need this anymore.  Might be superceded
299
                        //by MetacatPopulator
300
                        generateMissingSystemMetadata();
301
                        status = true;
302
                    }
303
                    else
304
                    {
305
                        String objectId = request.getPathInfo();
306
                        if (objectId != null && objectId.length() > 1)
307
                        {
308
                            objectId = request.getPathInfo().substring(1);
309
                        }
310
                        getSystemMetadataObject(objectId);
311
                        status = true;
312
                    }
313 5211 jones
314 5657 berkley
                } else if (resource.equals(RESOURCE_OBJECTS)) {
315 5691 berkley
                    System.out.println("Using resource 'object'");
316 5657 berkley
                    logMetacat.debug("D1 Rest: Starting resource processing...");
317
                    loadSessionData();
318 5211 jones
319 5657 berkley
                    String objectId = request.getPathInfo();
320
                    if (objectId != null && objectId.length() > 1)
321
                    {
322
                        objectId = request.getPathInfo().substring(1);
323
                    }
324
                    else
325
                    {
326
                        objectId = null;
327
                    }
328 5211 jones
329 5657 berkley
                    logMetacat.debug("verb:" + httpVerb);
330 5211 jones
331 5657 berkley
                    if (httpVerb == GET) {
332
                        getObject(objectId);
333
                        status = true;
334
                    } else if (httpVerb == POST) {
335
                        putObject(objectId, FUNCTION_NAME_INSERT);
336
                        status = true;
337
                    } else if (httpVerb == PUT) {
338
                        putObject(objectId, FUNCTION_NAME_UPDATE);
339
                        status = true;
340
                    } else if (httpVerb == DELETE) {
341
                        deleteObject(objectId);
342
                        status = true;
343
                    } else if (httpVerb == HEAD) {
344
                        describeObject(objectId);
345
                        status = true;
346
                    }
347
348 5211 jones
349 5657 berkley
                } else if (resource.equals(RESOURCE_IDENTIFIER)) {
350 5691 berkley
                    System.out.println("Using resource 'identifier'");
351 5657 berkley
                    String identifierId = request.getPathInfo();
352
                    if (identifierId != null && identifierId.length() > 1)
353
                        identifierId = request.getPathInfo().substring(1); //trim the slash
354 5211 jones
355 5657 berkley
                    if (httpVerb == GET) {
356
                        String op = params.get(FUNCTION_KEYWORD)[0];
357
                        if (op.equals(FUNCTION_NAME_ISREGISTERED)) {
358
                            isRegistered(identifierId);
359
                            status = true;
360
                        } else if (op.equals(FUNCTION_NAME_GETALLDOCS)) {
361
                            getAllDocIds();
362
                            status = true;
363
                        } else if (op.equals(FUNCTION_NAME_GETNEXTREV)) {
364
                            getNextRevision(identifierId);
365
                            status = true;
366
                        } else if (op.equals(FUNCTION_NAME_GETNEXTOBJ)) {
367
                            getNextObject();
368
                            status = true;
369
                        }
370 5446 jones
371 5657 berkley
                    } else if (httpVerb == PUT) {
372
                        //Earthgrid API > Identifier Service > addLSID Function
373
                        response.setStatus(501);
374
                        printError(
375
                                "This method is not supported by metacat.  To "
376
                                + "add a new LSID, add a document to metacat.",
377
                                response);
378
                        status = true;
379
                    }
380 5446 jones
381 5657 berkley
                } else if (resource.equals(RESOURCE_LOG)) {
382 5691 berkley
                    System.out.println("Using resource 'log'");
383 5657 berkley
                    //handle log events
384
                    if(httpVerb == GET)
385
                    {
386
                        getLog();
387
                        status = true;
388
                    }
389
                    else
390
                    {
391
                        //change to D1 spec for specifying which http methods are allowed for a resource
392
                        response.setStatus(501);
393
                        printError("POST, PUT, DELETE is not supported for logs.", response);
394
                        status = true;
395
                    }
396 5446 jones
397 5657 berkley
                } else if(resource.equals(RESOURCE_CHECKSUM)) {
398 5691 berkley
                    System.out.println("Using resource 'checksum'");
399 5657 berkley
                    //handle checksum requests
400
                    if(httpVerb == GET)
401
                    {
402
                        String guid = null;
403
                        String checksumAlgorithm = "MD5";
404
405
                        try
406
                        {
407
                           guid = params.get("id")[0];
408
                        }
409
                        catch(Exception e)
410
                        {
411
                            throw new InvalidRequest("1402", "Incorrect parameters passed to getChecksum");
412
                        }
413
414
                        Identifier guidid = new Identifier();
415
                        guidid.setValue(guid);
416
                        AuthToken token = new AuthToken(sessionId);
417
                        try
418
                        {
419
                            checksumAlgorithm = params.get("checksumAlgorithm")[0];
420
                        }
421
                        catch(Exception e)
422
                        {
423
                            //do nothing.  default to MD5
424
                        }
425
                        System.out.println("getting checksum for object " + guid +
426
                                " with algorithm " + checksumAlgorithm);
427
                        try
428
                        {
429
                            Checksum c = CrudService.getInstance().getChecksum(token, guidid, checksumAlgorithm);
430
                            System.out.println("got checksum " + c.getValue());
431
                            response.setStatus(200);
432
                            System.out.println("serializing response");
433
                            serializeServiceType(Checksum.class, c, response.getOutputStream());
434
                            System.out.println("done serializing response.");
435
                        }
436
                        catch(NotAuthorized na)
437
                        {
438
                            na.setDetail_code("1400");
439
                            serializeException(na, response.getOutputStream());
440
                        }
441
                        catch(NotFound nf)
442
                        {
443
                            nf.setDetail_code("1420");
444
                            serializeException(nf, response.getOutputStream());
445
                        }
446
                        catch(InvalidRequest ir)
447
                        {
448
                            ir.setDetail_code("1402");
449
                            serializeException(ir, response.getOutputStream());
450
                        }
451
                        catch(ServiceFailure sf)
452
                        {
453
                            sf.setDetail_code("1410");
454
                            serializeException(sf, response.getOutputStream());
455
                        }
456
                        catch(InvalidToken it)
457
                        {
458
                            it.setDetail_code("1430");
459
                            serializeException(it, response.getOutputStream());
460
                        }
461
                        status = true;
462
                    }
463
                }
464
465
                if (!status)
466
                {
467
                    response.setStatus(400);
468
                    printError("Incorrect parameters!", response);
469
                }
470 5211 jones
            } else {
471 5512 berkley
                response.setStatus(400);
472 5657 berkley
                printError("Incorrect resource!", response);
473 5211 jones
            }
474
        } catch (Exception e) {
475 5657 berkley
            logMetacat.error(e.getMessage());
476
            e.printStackTrace();
477 5211 jones
        }
478
    }
479 5374 berkley
480
    /**
481 5651 berkley
     * MN_crud.describe()
482
     * http://mule1.dataone.org/ArchitectureDocs/mn_api_crud.html#MN_crud.describe
483
     * @param guid
484
     */
485
    private void describeObject(String guid)
486
    {
487
        Logger logMetacat = Logger.getLogger(ResourceHandler.class);
488
        OutputStream out = null;
489
        try
490
        {
491
            out = response.getOutputStream();
492
        }
493
        catch(Exception e)
494
        {
495
            logMetacat.error("Error getting output stream in ResourceHandler.describeObject: " + e.getMessage());
496
            return;
497
        }
498
        response.setStatus(200);
499
        response.setContentType("text/xml");
500
        AuthToken token = new AuthToken(sessionId);
501
        CrudService cs = CrudService.getInstance();
502
        Identifier id = new Identifier();
503
        id.setValue(guid);
504
        try
505
        {
506
            DescribeResponse dr = cs.describe(token, id);
507
            DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SZ");
508
            response.addHeader("guid", guid);
509
            response.addHeader("checksum", dr.getDataONE_Checksum().getValue());
510 5652 berkley
            response.addHeader("checksum_algorithm", dr.getDataONE_Checksum().getAlgorithm().name());
511 5651 berkley
            response.addHeader("content_length", dr.getContent_Length() + "");
512
            response.addHeader("last_modified", dateFormat.format(dr.getLast_Modified()));
513
            response.addHeader("format", dr.getDataONE_ObjectFormat().toString());
514
        }
515
        catch(InvalidRequest ir)
516
        {
517
            serializeException(ir, out);
518
        }
519
        catch(NotImplemented ni)
520
        {
521
            serializeException(ni, out);
522
        }
523
        catch(NotAuthorized na)
524
        {
525
            serializeException(na, out);
526
        }
527
        catch(ServiceFailure sf)
528
        {
529
            serializeException(sf, out);
530
        }
531
        catch(NotFound nf)
532
        {
533
            serializeException(nf, out);
534
        }
535
        catch(InvalidToken it)
536
        {
537
            serializeException(it, out);
538
        }
539
    }
540
541
    /**
542 5390 berkley
     * get the logs from the CrudService based on passed params.  Available
543
     * params are token, fromDate, toDate, event.  See
544
     * http://mule1.dataone.org/ArchitectureDocs/mn_api_crud.html#MN_crud.getLogRecords
545
     * for more info
546
     */
547
    private void getLog()
548
    {
549
        OutputStream out = null;
550
        try
551
        {
552
            out = response.getOutputStream();
553 5515 berkley
            response.setStatus(200);
554 5450 berkley
            response.setContentType("text/xml");
555 5390 berkley
            AuthToken token = new AuthToken(sessionId);
556
            String fromDateS = params.get("fromDate")[0];
557 5418 berkley
            System.out.println("param fromDateS: " + fromDateS);
558 5390 berkley
            Date fromDate = null;
559
            String toDateS = params.get("toDate")[0];
560 5418 berkley
            System.out.println("param toDateS: " + toDateS);
561 5390 berkley
            Date toDate = null;
562
            String eventS = params.get("event")[0];
563
            Event event = null;
564
            if(fromDateS != null)
565
            {
566 5429 berkley
                //fromDate = dateFormat.parse(fromDateS);
567
                fromDate = parseDateAndConvertToGMT(fromDateS);
568 5390 berkley
            }
569
            if(toDateS != null)
570
            {
571 5429 berkley
                //toDate = dateFormat.parse(toDateS);
572
                toDate = parseDateAndConvertToGMT(toDateS);
573 5390 berkley
            }
574
            if(eventS != null)
575
            {
576
                event = Event.convert(eventS);
577
            }
578 5418 berkley
            System.out.println("fromDate: " + fromDate + " toDate: " + toDate);
579 5395 berkley
580 5418 berkley
            System.out.println("calling crudservice.getLogRecords");
581 5390 berkley
            Log log = CrudService.getInstance().getLogRecords(token, fromDate, toDate, event);
582
            serializeServiceType(Log.class, log, out);
583
        }
584
        catch(Exception e)
585
        {
586
            String msg = "Could not get logs from CrudService: " + e.getMessage();
587 5617 berkley
            response.setStatus(500);
588 5390 berkley
            ServiceFailure sf = new ServiceFailure("1490", msg);
589
            logMetacat.error(msg);
590
            e.printStackTrace();
591
            serializeException(sf, out);
592
        }
593
    }
594
595
    /**
596 5374 berkley
     *  copies request parameters to a hashtable which is given as argument to native metacathandler functions
597
     */
598
    private void initParams() {
599 5211 jones
600 5374 berkley
        String name = null;
601
        String[] value = null;
602
        Enumeration paramlist = request.getParameterNames();
603
        while (paramlist.hasMoreElements()) {
604
            name = (String) paramlist.nextElement();
605
            value = request.getParameterValues(name);
606
            params.put(name, value);
607
        }
608
    }
609
610 5211 jones
    /**
611 5374 berkley
     *
612
     * Load user details of metacat session from the request
613
     *
614
     */
615
    private void loadSessionData()
616
      throws Exception
617
    {
618
        SessionData sessionData = RequestUtil.getSessionData(request);
619
        try
620
        {
621
            username = null;
622
            password = null;
623
            groupNames = null;
624
            sessionId = null;
625
626
            boolean validSession = false;
627
            SessionService ss = SessionService.getInstance();
628 5410 berkley
            System.out.println("sessionData: " + sessionData);
629 5423 berkley
            if(sessionData == null)
630
            {
631
                username = "public";
632
                sessionId = "0";
633
                System.out.println("sessiondata is null.  Creating a public session.");
634
                return;
635
            }
636
637 5410 berkley
            System.out.println("username: " + sessionData.getUserName());
638
            System.out.println("sessionid: " + sessionData.getId());
639 5374 berkley
            //validate the session
640 5410 berkley
            if(ss.isSessionRegistered(sessionData.getId()) &&
641
               !(sessionData.getUserName().equals("public") || sessionData.getId().equals("0")))
642 5374 berkley
            {
643
                validSession = true;
644
            }
645
646
            if(validSession)
647
            {
648
                //if the session is valid, set these variables
649
                username = sessionData.getUserName();
650
                password = sessionData.getPassword();
651
                groupNames = sessionData.getGroupNames();
652
                sessionId = sessionData.getId();
653 5386 berkley
                System.out.println("setting sessionid to " + sessionId);
654
                System.out.println("username: " + username);
655 5374 berkley
            }
656
657
            //if the session is not valid or the username is null, set
658
            //username to public
659
            if (username == null)
660
            {
661 5386 berkley
                System.out.println("setting username to public.");
662 5374 berkley
                username = "public";
663
            }
664
        }
665
        catch(Exception e)
666
        {
667 5423 berkley
            e.printStackTrace();
668 5374 berkley
            throw new Exception("Could not load the session data: " + e.getMessage());
669
        }
670
    }
671
672
    /**
673
     * generate missing system metadata for any science metadata objects
674
     * that don't already have it. https://trac.dataone.org/ticket/591
675 5381 berkley
     *
676
     * called with POST meta/?op=generatemissingsystemmetadata
677 5374 berkley
     */
678
    private void generateMissingSystemMetadata()
679
    {
680 5381 berkley
        AuthToken token = new AuthToken(sessionId);
681
        CrudService.getInstance().generateMissingSystemMetadata(token);
682 5374 berkley
    }
683
684
    /**
685
     *  Earthgrid API > Identifier Service > isRegistered Function :
686
     *  calls MetacatHandler > handleIdIsRegisteredAction
687 5286 jones
     * @param guid
688 5211 jones
     * @throws IOException
689
     */
690 5286 jones
    private void isRegistered(String guid) throws IOException
691
    {
692
693
        // Look up the localId for this guid
694
        IdentifierManager im = IdentifierManager.getInstance();
695
        String localId = "";
696
        try {
697
            localId = im.getLocalId(guid);
698
        } catch (McdbDocNotFoundException e) {
699
            // TODO: Need to return the proper DataONE exception
700
        }
701
702
        params.put("docid", new String[] { localId });
703 5211 jones
        PrintWriter out = response.getWriter();
704 5515 berkley
        response.setStatus(200);
705 5450 berkley
        response.setContentType("text/xml");
706 5211 jones
        handler.handleIdIsRegisteredAction(out, params, response);
707
        out.close();
708
    }
709
710
    /**
711 5374 berkley
     * Earthgrid API > Identifier Service > getAllDocIds Function :
712
     * calls MetacatHandler > handleGetAllDocidsAction
713 5211 jones
     * @throws IOException
714
     */
715
    private void getAllDocIds() throws IOException {
716
        PrintWriter out = response.getWriter();
717 5515 berkley
        response.setStatus(200);
718 5450 berkley
        response.setContentType("text/xml");
719 5211 jones
        handler.handleGetAllDocidsAction(out, params, response);
720
        out.close();
721
    }
722
723
    /**
724 5374 berkley
     * Earthgrid API > Identifier Service > getNextRevision Function :
725
     * calls MetacatHandler > handleGetRevisionAndDocTypeAction
726 5286 jones
     * @param guid
727 5211 jones
     * @throws IOException
728
     */
729 5286 jones
    private void getNextRevision(String guid) throws IOException
730
    {
731
        params.put("docid", new String[] { guid });
732 5211 jones
        PrintWriter out = response.getWriter();
733 5515 berkley
        response.setStatus(200);
734 5450 berkley
        response.setContentType("text/xml");
735 5211 jones
        //handler.handleGetRevisionAndDocTypeAction(out, params);
736
737
        try {
738
            // Make sure there is a docid
739 5286 jones
            if (guid == null || guid.equals("")) {
740 5211 jones
                throw new Exception("User didn't specify docid!");
741 5286 jones
            }
742 5211 jones
743 5286 jones
            // Look up the localId for this guid
744
            IdentifierManager im = IdentifierManager.getInstance();
745
            String localId = "";
746
            try {
747
                localId = im.getLocalId(guid);
748
            } catch (McdbDocNotFoundException e) {
749
                // TODO: Need to return the proper DataONE exception
750
            }
751
752 5211 jones
            // Create a DBUtil object
753
            DBUtil dbutil = new DBUtil();
754
            // Get a rev and doctype
755
            String revAndDocType = dbutil
756 5286 jones
                    .getCurrentRevisionAndDocTypeForGivenDocument(localId);
757 5211 jones
            int revision = Integer.parseInt(revAndDocType.split(";")[0]) + 1;
758
759
            out.println("<?xml version=\"1.0\"?>");
760
            out.print("<next-revision>");
761
            out.print(revision);
762
            out.print("</next-revision>");
763
764
        } catch (Exception e) {
765
            // Handle exception
766 5512 berkley
            response.setStatus(500);
767 5211 jones
            out.println("<?xml version=\"1.0\"?>");
768
            out.println("<error>");
769
            out.println(e.getMessage());
770
            out.println("</error>");
771
        }
772
773
        out.close();
774
    }
775
776
    /**
777 5374 berkley
     * Earthgrid API > Identifier Service > getNextObject Function :
778
     * calls MetacatHandler > handleGetMaxDocidAction
779 5211 jones
     * @throws IOException
780
     */
781
    private void getNextObject() throws IOException {
782
        PrintWriter out = response.getWriter();
783 5515 berkley
        response.setStatus(200);
784 5450 berkley
        response.setContentType("text/xml");
785 5211 jones
        handler.handleGetMaxDocidAction(out, params, response);
786
        out.close();
787
    }
788
789
    /**
790 5299 jones
     * Implements REST version of DataONE CRUD API --> get
791 5282 jones
     * @param guid ID of data object to be read
792 5211 jones
     */
793 5450 berkley
    private void getObject(String guid) {
794
        CrudService cs = CrudService.getInstance();
795
        cs.setParamsFromRequest(request);
796
        AuthToken token = new AuthToken(sessionId);
797
        OutputStream out = null;
798
        try {
799
            out = response.getOutputStream();
800 5515 berkley
            response.setStatus(200);
801 5450 berkley
            response.setContentType("text/xml");
802
            if(guid != null)
803
            { //get a specific document
804
                Identifier id = new Identifier();
805
                id.setValue(guid);
806
                try
807
                {
808
                    if(token == null)
809
                    {
810
                        token = new AuthToken("Public");
811
                    }
812
                    InputStream data = cs.get(token, id);
813
                    IOUtils.copyLarge(data, response.getOutputStream());
814
                }
815
                catch(InvalidToken it)
816
                {
817 5617 berkley
                    response.setStatus(500);
818 5450 berkley
                    serializeException(it, out);
819
                }
820
                catch(ServiceFailure sf)
821
                {
822 5617 berkley
                    response.setStatus(500);
823 5450 berkley
                    serializeException(sf, out);
824
                }
825
                catch(NotAuthorized na)
826
                {
827 5617 berkley
                    response.setStatus(500);
828 5450 berkley
                    serializeException(na, out);
829
                }
830
                catch(NotFound nf)
831
                {
832 5617 berkley
                    response.setStatus(500);
833 5450 berkley
                    serializeException(nf, out);
834
                }
835
                catch(NotImplemented ni)
836
                {
837 5617 berkley
                    response.setStatus(500);
838 5450 berkley
                    serializeException(ni, out);
839
                }
840
                catch(Exception e)
841
                {
842 5617 berkley
                    response.setStatus(500);
843 5450 berkley
                    System.out.println("Error with Crud.get().  " +
844
                            "If this is an 'Exception producing data' error, " +
845
                            "go to CrudService.get() for better debugging.  " +
846
                            "Here's the error: " + e.getMessage());
847
                    e.printStackTrace();
848
                    ServiceFailure sf = new ServiceFailure("1030",
849
                            "IO Error in ResourceHandler.getObject: " + e.getMessage());
850
                    serializeException(sf, out);
851
                }
852
            }
853
            else
854
            { //call listObjects with specified params
855
                Date startTime = null;
856
                Date endTime = null;
857
                ObjectFormat objectFormat = null;
858
                boolean replicaStatus = false;
859
                int start = 0;
860 5481 berkley
                //TODO: make the max count into a const
861 5450 berkley
                int count = 1000;
862
                Enumeration paramlist = request.getParameterNames();
863
                while (paramlist.hasMoreElements())
864
                { //parse the params and make the crud call
865
                    String name = (String) paramlist.nextElement();
866
                    String[] value = (String[])request.getParameterValues(name);
867
                    /*for(int i=0; i<value.length; i++)
868
                    {
869
                        System.out.println("name: " + name + " value: " + value[i]);
870
                    }*/
871
                    if(name.equals("startTime") && value != null)
872
                    {
873
                        try
874
                        {
875
                          //startTime = dateFormat.parse(value[0]);
876
                            startTime = parseDateAndConvertToGMT(value[0]);
877
                        }
878
                        catch(Exception e)
879
                        {  //if we can't parse it, just don't use the startTime param
880
                            System.out.println("Could not parse startTime: " + value[0]);
881
                            startTime = null;
882
                        }
883
                    }
884
                    else if(name.equals("endTime") && value != null)
885
                    {
886
                        try
887
                        {
888
                          //endTime = dateFormat.parse(value[0]);
889
                            endTime = parseDateAndConvertToGMT(value[0]);
890
                        }
891
                        catch(Exception e)
892
                        {  //if we can't parse it, just don't use the endTime param
893
                            System.out.println("Could not parse endTime: " + value[0]);
894
                            endTime = null;
895
                        }
896
                    }
897
                    else if(name.equals("objectFormat") && value != null)
898
                    {
899
                        objectFormat = ObjectFormat.convert(value[0]);
900
                    }
901
                    else if(name.equals("replicaStatus") && value != null)
902
                    {
903
                        if(value != null &&
904
                           value.length > 0 &&
905
                           (value[0].equals("true") || value[0].equals("TRUE") || value[0].equals("YES")))
906
                        {
907
                            replicaStatus = true;
908
                        }
909
                    }
910
                    else if(name.equals("start") && value != null)
911
                    {
912
                        start = new Integer(value[0]).intValue();
913
                    }
914
                    else if(name.equals("count") && value != null)
915
                    {
916
                        count = new Integer(value[0]).intValue();
917
                    }
918
                }
919
                //make the crud call
920 5510 berkley
                System.out.println("token: " + token + " startTime: " + startTime +
921 5450 berkley
                        " endtime: " + endTime + " objectFormat: " +
922
                        objectFormat + " replicaStatus: " + replicaStatus +
923
                        " start: " + start + " count: " + count);
924 5510 berkley
925 5450 berkley
                ObjectList ol = cs.listObjects(token, startTime, endTime,
926
                        objectFormat, replicaStatus, start, count);
927
928
                StringReader sr = new StringReader(ol.toString());
929 5515 berkley
                out = response.getOutputStream();
930
                response.setStatus(200);
931 5450 berkley
                response.setContentType("text/xml");
932
                // Serialize and write it to the output stream
933
934
                try {
935
                    serializeServiceType(ObjectList.class, ol, out);
936
                } catch (JiBXException e) {
937
                    throw new ServiceFailure("1190", "Failed to serialize ObjectList: " + e.getMessage());
938
                }
939
            }
940
        } catch (BaseException e) {
941 5617 berkley
                response.setStatus(500);
942 5450 berkley
                serializeException(e, out);
943
        } catch (IOException e) {
944
            e.printStackTrace();
945 5617 berkley
            response.setStatus(500);
946 5450 berkley
            ServiceFailure sf = new ServiceFailure("1030",
947
                    "IO Error in ResourceHandler.getObject: " + e.getMessage());
948
            serializeException(sf, out);
949
        } catch(NumberFormatException ne) {
950 5617 berkley
            response.setStatus(500);
951 5450 berkley
            InvalidRequest ir = new InvalidRequest("1030", "Invalid format for parameter: " + ne.getMessage());
952
            serializeException(ir, out);
953
        } catch (Exception e) {
954
            e.printStackTrace();
955 5617 berkley
            response.setStatus(500);
956 5450 berkley
            ServiceFailure sf = new ServiceFailure("1030",
957
                    "Exception " + e.getClass().getName() + " raised while handling listObjects request: " +
958
                    e.getMessage());
959
            serializeException(sf, out);
960
        }
961
    }
962 5428 berkley
963
    /**
964
     * parse a date and return it in GMT if it ends with a 'Z'
965
     * @param date
966
     * @return
967
     * @throws ParseException
968
     */
969
    private Date parseDateAndConvertToGMT(String date) throws ParseException
970
    {
971 5429 berkley
        try
972
        {   //the format we want
973
            return dateFormat.parse(date);
974
        }
975
        catch(java.text.ParseException pe)
976
        {   //try another legacy format
977
            DateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'");
978
            dateFormat2.setTimeZone(TimeZone.getTimeZone("GMT-0"));
979
            return dateFormat2.parse(date);
980
        }
981 5428 berkley
    }
982 5211 jones
983
    /**
984 5332 jones
     * Implements REST version of DataONE CRUD API --> getSystemMetadata
985
     * @param guid ID of data object to be read
986
     */
987
    private void getSystemMetadataObject(String guid) {
988 5337 berkley
        CrudService cs = CrudService.getInstance();
989
        cs.setParamsFromRequest(request);
990 5386 berkley
        AuthToken token = new AuthToken(sessionId);
991 5332 jones
        OutputStream out = null;
992
        try {
993 5450 berkley
            response.setContentType("text/xml");
994 5515 berkley
            response.setStatus(200);
995 5332 jones
            out = response.getOutputStream();
996
            Identifier id = new Identifier();
997
            id.setValue(guid);
998
            SystemMetadata sysmeta = cs.getSystemMetadata(token, id);
999
1000
            // Serialize and write it to the output stream
1001
            try {
1002 5481 berkley
                //TODO: look at the efficiency of this method.  The system metadata
1003
                //is read from metacat (in CrudService) as xml, then serialized
1004
                //to a SystemMetadat object, then returned here, then serizlized
1005
                //back to XML to be sent to the response.
1006 5390 berkley
                serializeServiceType(SystemMetadata.class, sysmeta, out);
1007 5332 jones
            } catch (JiBXException e) {
1008 5356 berkley
                throw new ServiceFailure("1190", "Failed to serialize SystemMetadata: " + e.getMessage());
1009 5332 jones
            }
1010
        } catch (BaseException e) {
1011 5617 berkley
            response.setStatus(500);
1012 5332 jones
                serializeException(e, out);
1013
        } catch (IOException e) {
1014 5617 berkley
            response.setStatus(500);
1015 5414 berkley
            ServiceFailure sf = new ServiceFailure("1030",
1016
                    "Error in ResourceHandler.getSystemMetadataObject: " + e.getMessage());
1017 5332 jones
            serializeException(sf, out);
1018
        } finally {
1019
            IOUtils.closeQuietly(out);
1020
        }
1021
    }
1022
1023
    /**
1024 5390 berkley
     * serialize an object of type to out
1025
     * @param type the class of the object to serialize (i.e. SystemMetadata.class)
1026
     * @param object the object to serialize
1027
     * @param out the stream to serialize it to
1028
     * @throws JiBXException
1029
     */
1030
    private void serializeServiceType(Class type, Object object, OutputStream out)
1031
      throws JiBXException
1032
    {
1033
        IBindingFactory bfact = BindingDirectory.getFactory(type);
1034
        IMarshallingContext mctx = bfact.createMarshallingContext();
1035
        mctx.marshalDocument(object, "UTF-8", null, out);
1036
    }
1037
1038
    /**
1039
     * deserialize an object of type from is
1040
     * @param type the class of the object to serialize (i.e. SystemMetadata.class)
1041
     * @param is the stream to deserialize from
1042
     * @throws JiBXException
1043
     */
1044
    private Object deserializeServiceType(Class type, InputStream is)
1045
      throws JiBXException
1046
    {
1047
        IBindingFactory bfact = BindingDirectory.getFactory(type);
1048
        IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
1049
        Object o = (Object) uctx.unmarshalDocument(is, null);
1050
        return o;
1051
    }
1052
1053
    /**
1054 5211 jones
     * Earthgrid API > Query Service > Query Function : translates ecogrid query document to metacat query
1055
     * then calls DBQuery > createResultDocument function and then again translate resultset to ecogrid resultset
1056
     *
1057
     * NOTE:
1058
     *      This is the only method that uses EcoGrid classes for its implementation.
1059
     *      It does so because it takes an EcoGrid Query as input, and outputs an
1060
     *      EcoGrid ResultSet document.  These documents are parsed by the auto-generated
1061
     *      EcoGrid classes from axis, and so we link to them here rather than re-inventing them.
1062
     *      This creates a circular dependency, because the Metacat classes are needed
1063
     *      to build the EcoGrid implementation, and the EcoGrid jars are needed to build this query()
1064
     *      method.  This circularity could be resolved by moving the EcoGrid classes
1065
     *      to Metacat directly.  As we transition away from EcoGrid SOAP methods in
1066
     *      favor of these REST interfaces, this circular dependency can be eliminated.
1067
     *
1068
     * @throws Exception
1069
     */
1070
    private void query() throws Exception {
1071
        /*  This block commented out because of the EcoGrid circular dependency.
1072
         *  For now, query will not be supported until the circularity can be
1073 5286 jones
         *  resolved, probably by moving the ecogrid query syntax transformers
1074 5211 jones
         *  directly into the Metacat codebase.  MBJ 2010-02-03
1075
1076
        try {
1077
            EcogridQueryParser parser = new EcogridQueryParser(request
1078
                    .getReader());
1079
            parser.parseXML();
1080
            QueryType queryType = parser.getEcogridQuery();
1081
            EcogridJavaToMetacatJavaQueryTransformer queryTransformer =
1082
                new EcogridJavaToMetacatJavaQueryTransformer();
1083
            QuerySpecification metacatQuery = queryTransformer
1084
                    .transform(queryType);
1085
1086
            DBQuery metacat = new DBQuery();
1087
1088
            boolean useXMLIndex = (new Boolean(PropertyService
1089
                    .getProperty("database.usexmlindex"))).booleanValue();
1090
            String xmlquery = "query"; // we don't care the query in resultset,
1091
            // the query can be anything
1092
            PrintWriter out = null; // we don't want metacat result, so set out null
1093
1094
            // parameter: queryspecification, user, group, usingIndexOrNot
1095
            StringBuffer result = metacat.createResultDocument(xmlquery,
1096
                    metacatQuery, out, username, groupNames, useXMLIndex);
1097
1098 5657 berkley
            // create result set transfer
1099 5211 jones
            String saxparser = PropertyService.getProperty("xml.saxparser");
1100
            MetacatResultsetParser metacatResultsetParser = new MetacatResultsetParser(
1101
                    new StringReader(result.toString()), saxparser, queryType
1102
                            .getNamespace().get_value());
1103
            ResultsetType records = metacatResultsetParser.getEcogridResult();
1104
1105
            System.out
1106
                    .println(EcogridResultsetTransformer.toXMLString(records));
1107
            response.setContentType("text/xml");
1108
            out = response.getWriter();
1109
            out.print(EcogridResultsetTransformer.toXMLString(records));
1110
1111
        } catch (Exception e) {
1112
            e.printStackTrace();
1113
        }*/
1114
        response.setContentType("text/xml");
1115 5512 berkley
        response.setStatus(501);
1116 5211 jones
        PrintWriter out = response.getWriter();
1117
        out.print("<error>Query operation not yet supported by Metacat.</error>");
1118
        out.close();
1119
    }
1120 5319 jones
1121 5394 berkley
    private String streamToString(InputStream is)
1122
    throws IOException
1123
    {
1124 5629 berkley
        return IOUtil.toString(is);
1125 5394 berkley
    }
1126
1127
    private InputStream stringToStream(String s)
1128
    throws IOException
1129
    {
1130
        ByteArrayInputStream bais = new ByteArrayInputStream(s.getBytes());
1131
        return bais;
1132
    }
1133
1134 5462 berkley
    /**
1135
     * process a mime multipart message
1136
     * @param is
1137
     * @return
1138
     */
1139 5636 berkley
    /*private Hashtable processMMP(InputStream is)
1140 5462 berkley
      throws IOException
1141
    {
1142 5481 berkley
        //TODO: verify that this is how the RFC for MMP should work
1143
        //SORTAHACK: Since mmp seems to have a bug where large object parts get truncated,
1144 5462 berkley
        //parse the stream here.  This has the disavantage of putting the
1145
        //stream into memory.
1146
        InputStream object = null;
1147
        InputStream sysmeta = null;
1148 5616 berkley
        String s = IOUtils.toString(is);
1149 5636 berkley
        System.out.println("mime: " + s);
1150 5462 berkley
        //figure out what the boundary marker is
1151
        String searchString = "boundary=";
1152
        int searchStringIndex = s.indexOf(searchString);
1153
        String boundary = s.substring(searchStringIndex + searchString.length() + 1,
1154
                s.indexOf("\"", searchStringIndex + searchString.length() + 1));
1155
        boundary = "--" + boundary;
1156
        //System.out.println("boundary is " + boundary);
1157
1158
        //find the system metadata
1159
        searchString = "Content-Disposition: attachment; filename=systemmetadata";
1160
        searchStringIndex = s.indexOf(searchString);
1161 5616 berkley
        String sm = s.substring(searchStringIndex +
1162
                searchString.length() + 2,
1163
                s.indexOf(boundary, searchStringIndex));
1164
        sysmeta = new ByteArrayInputStream(sm.getBytes());
1165 5462 berkley
1166
        //find the object
1167
        searchString = "Content-Disposition: attachment; filename=object";
1168
        searchStringIndex = s.indexOf(searchString);
1169 5616 berkley
        String o = s.substring(searchStringIndex +
1170
                searchString.length() + 2,
1171
                s.indexOf(boundary, searchStringIndex));
1172
        object = new ByteArrayInputStream(o.getBytes());
1173 5462 berkley
1174
        Hashtable h = new Hashtable();
1175
        h.put("object", object);
1176
        h.put("systemmetadata", sysmeta);
1177 5616 berkley
1178 5617 berkley
        //System.out.println("o: \"" + o + "\"");
1179
        //System.out.println("sm: \"" + sm + "\"");
1180 5462 berkley
        return h;
1181
    }
1182 5636 berkley
    */
1183 5637 berkley
1184 5639 berkley
    protected static String[] findBoundaryString(InputStream is)
1185 5637 berkley
        throws IOException
1186 5629 berkley
    {
1187 5639 berkley
        String[] endResult = new String[2];
1188 5637 berkley
        String boundary = "";
1189 5639 berkley
        String searchString = "boundary=";
1190
        boolean doneWithCurrentArray = false;
1191 5637 berkley
        byte[] b = new byte[1024];
1192 5639 berkley
        int numbytes = is.read(b, 0, 1024);
1193
        while(numbytes != -1)
1194 5636 berkley
        {
1195 5639 berkley
            String s = new String(b, 0, numbytes);
1196
1197
            int[] result = StreamUtil.lookForMatch(searchString, s);
1198
            int searchStringIndex = s.indexOf(searchString);
1199
            if(s.indexOf("\"", searchStringIndex + searchString.length() + 1) == -1)
1200
            { //the end of the boundary is in the next byte array
1201
                boundary = s.substring(searchStringIndex + searchString.length() + 1, s.length());
1202
            }
1203
            else if(!boundary.startsWith("--"))
1204
            { //we can read the whole boundary from this byte array
1205
                boundary = s.substring(searchStringIndex + searchString.length() + 1,
1206
                    s.indexOf("\"", searchStringIndex + searchString.length() + 1));
1207
                boundary = "--" + boundary;
1208
                endResult[0] = boundary;
1209
                endResult[1] = s.substring(s.indexOf("\"", searchStringIndex + searchString.length() + 1) + 1,
1210
                        s.length());
1211
                break;
1212
            }
1213
            else
1214
            { //we're now reading the 2nd byte array to get the rest of the boundary
1215
                searchString = "\"";
1216
                searchStringIndex = s.indexOf(searchString);
1217
                boundary += s.substring(0, searchStringIndex);
1218
                boundary = "--" + boundary;
1219
                endResult[0] = boundary;
1220
                endResult[1] = s.substring(s.indexOf("\"", searchStringIndex + searchString.length() + 1) + 1,
1221
                        s.length());
1222
                break;
1223
            }
1224 5637 berkley
        }
1225 5639 berkley
        System.out.println("boundary is: " + boundary);
1226
        return endResult;
1227
    }
1228
1229
    protected String writeMMPPartToFile(String beginSearch,
1230
            InputStream is, String boundary, String searchString, File f)
1231
        throws IOException
1232
    {
1233 5640 berkley
        Logger logMetacat = Logger.getLogger(ResourceHandler.class);
1234
        logMetacat.info("writing MMP parts");
1235 5670 berkley
        //String s = beginSearch;
1236
        String s = null;
1237 5639 berkley
        FileOutputStream fos = new FileOutputStream(f);
1238
        int numread = 0;
1239
        byte[] b = new byte[1024];
1240
        String writeString = "";
1241
1242
        if(s == null)
1243
        {   //starting with the first part of the stream
1244
            numread = is.read(b, 0, 1024);
1245
            s = new String(b, 0, numread);
1246 5637 berkley
        }
1247
1248 5670 berkley
        if(beginSearch != null)
1249
        {
1250
            s = beginSearch + s;
1251
        }
1252
1253 5639 berkley
        boolean useCurrentS = true;
1254
        boolean searchForBoundary = false;
1255
        String seekString = searchString;
1256 5637 berkley
1257
        while(numread != -1)
1258
        {
1259 5640 berkley
            logMetacat.info("////////////////////////iterating");
1260
            logMetacat.info("searchForBoundary: " + searchForBoundary);
1261
            logMetacat.info("useCurrentS: " + useCurrentS);
1262 5670 berkley
            logMetacat.info("seekString: " + seekString);
1263
            logMetacat.info("in string: " + s);
1264 5639 berkley
            if(searchForBoundary)
1265 5636 berkley
            {
1266 5639 berkley
                seekString = boundary;
1267 5637 berkley
            }
1268
            else
1269
            {
1270 5639 berkley
                seekString = searchString;
1271 5637 berkley
            }
1272
1273 5639 berkley
            int[] result = StreamUtil.lookForMatch(seekString, s);
1274
            if(!useCurrentS)
1275 5637 berkley
            {
1276
                numread = is.read(b, 0, 1024);
1277 5639 berkley
                if(numread != -1)
1278
                {
1279
                    s = new String(b, 0, numread);
1280
                }
1281
                else
1282
                {
1283
                    break;
1284
                }
1285 5637 berkley
            }
1286
1287 5670 berkley
            logMetacat.info("2seekString: " + seekString);
1288
            logMetacat.info("2in string: " + s);
1289 5637 berkley
1290 5639 berkley
            if(result[0] >= 0 && result[1] == seekString.length())
1291
            {
1292 5640 berkley
                //searchString is full in s
1293
                logMetacat.info("seekstring is fully in s");
1294 5639 berkley
                if(!searchForBoundary)
1295
                {   //we're looking for searchString and we found it
1296
                    //chop off the searchString itself and start writing
1297
                    //until we find boundary
1298
                    s = s.substring(result[0] + result[1], s.length());
1299
                    if(s.length() > 0)
1300 5638 berkley
                    {
1301 5639 berkley
                        useCurrentS = true;
1302 5638 berkley
                    }
1303
                    else
1304
                    {
1305 5639 berkley
                        useCurrentS = false;
1306 5638 berkley
                    }
1307 5639 berkley
                    searchForBoundary = true;
1308 5638 berkley
                }
1309 5639 berkley
                else
1310
                {   //we're writing, but we found the boundary in this chunk
1311 5637 berkley
1312 5639 berkley
                    writeString = s.substring(0, result[0]);
1313 5657 berkley
                    //System.out.println("writing1: " + writeString);
1314 5639 berkley
                    fos.write(writeString.getBytes());
1315
                    //we're done.  break and return;
1316
                    return s.substring(result[0] + result[1], s.length());
1317 5637 berkley
                }
1318
            }
1319 5639 berkley
            else if(result[0] > 0 && result[1] != seekString.length())
1320
            {
1321 5640 berkley
                logMetacat.info("seekstring is partially in s");
1322 5639 berkley
                //seekString is partially in s
1323
                //more specifically, the beginning of seekString is at the end
1324
                //of s
1325
1326
                //get the next chunk right now, see if the beginning matches
1327
                numread = is.read(b, 0, 1024);
1328
                String s2 = new String(b, 0, numread);
1329
                s += s2;
1330 5640 berkley
                useCurrentS = true;
1331 5637 berkley
            }
1332
            else
1333
            {
1334 5640 berkley
                logMetacat.info("seekstring is not in s");
1335 5639 berkley
                //searchString is not in s
1336 5637 berkley
                if(searchForBoundary)
1337
                {
1338 5657 berkley
                    //System.out.println("writing2: " + s);
1339 5639 berkley
                    fos.write(s.getBytes());
1340 5636 berkley
                }
1341 5639 berkley
                numread = is.read(b, 0, 1024);
1342
                if(numread != -1)
1343
                {
1344
                    s = new String(b, 0, numread);
1345
                }
1346
                else
1347
                {
1348
                    break;
1349
                }
1350 5640 berkley
                useCurrentS = true;
1351 5636 berkley
            }
1352 5637 berkley
        }
1353 5639 berkley
        return "";
1354
    }
1355
1356
    protected Hashtable<String, File> writeMMPPartsToFiles(InputStream is)
1357
        throws IOException
1358
    {
1359 5640 berkley
        Logger logMetacat = Logger.getLogger(ResourceHandler.class);
1360
        logMetacat.info("Processing Mime Multipart");
1361 5639 berkley
        String[] boundaryResults = findBoundaryString(is);
1362
        String boundary = boundaryResults[0];
1363
        String s = boundaryResults[1];
1364
        String[] searchStrings = {
1365
                "Content-Disposition: attachment; filename=systemmetadata\n\n",
1366
                "Content-Disposition: attachment; filename=object\n\n"};
1367 5637 berkley
1368 5639 berkley
        File[] fileArr = getMMPTempFiles();
1369 5638 berkley
        Hashtable<String, File> h = new Hashtable<String, File>();
1370 5640 berkley
        //System.out.println("==========================Looking for SM");
1371
        //System.out.println("writing sm to " + fileArr[0].getAbsolutePath());
1372
        logMetacat.info("writing mime system metadata to " + fileArr[0].getAbsolutePath());
1373 5670 berkley
        s = writeMMPPartToFile(s.trim(), is, boundary, searchStrings[0], fileArr[0]);
1374
        logMetacat.info("writeMMPPartToFile returned '" + s.trim() + "' after processing the system metadata");
1375 5640 berkley
        //System.out.println("==========================Looking for Object");
1376
        //System.out.println("writing obj to " + fileArr[1].getAbsolutePath());
1377
        logMetacat.info("writing mime object to " + fileArr[1].getAbsolutePath());
1378 5670 berkley
        writeMMPPartToFile(s.trim(), is, boundary, searchStrings[1], fileArr[1]);
1379 5639 berkley
        h.put("sysmeta", fileArr[0]);
1380
        h.put("object", fileArr[1]);
1381 5638 berkley
        return h;
1382 5637 berkley
    }
1383
1384 5639 berkley
    private static File[] getMMPTempFiles()
1385
        throws IOException
1386
    {
1387
        Logger logMetacat = Logger.getLogger(ResourceHandler.class);
1388
        File tmpDir;
1389
        try
1390
        {
1391
            tmpDir = new File(PropertyService.getProperty("application.tempDir"));
1392
        }
1393
        catch(PropertyNotFoundException pnfe)
1394
        {
1395
            logMetacat.error("ResourceHandler.writeMMPPartstoFiles: " +
1396
                    "application.tmpDir not found.  Using /tmp instead.");
1397
            tmpDir = new File("/tmp");
1398
        }
1399
        long datetimetag = new Date().getTime();
1400
        File smFile = new File(tmpDir, "sm." + datetimetag + ".tmp");
1401
        File objFile = new File(tmpDir, "obj." + datetimetag + ".tmp");
1402
        File[] fileArr = {smFile, objFile};
1403
        return fileArr;
1404
    }
1405
1406 5637 berkley
    /**
1407
     * return a vector where the first element is a string that represents the system
1408
     * metadata and the 2nd element is an InputStream that is the object
1409
     */
1410 5638 berkley
    protected Hashtable<String, File> processMMP(final InputStream is)
1411 5637 berkley
      throws IOException
1412
    {
1413
        return writeMMPPartsToFiles(is);
1414 5636 berkley
    }
1415 5462 berkley
1416 5211 jones
    /**
1417
     * Earthgrid API > Put Service >Put Function : calls MetacatHandler > handleInsertOrUpdateAction
1418
     *
1419 5319 jones
     * @param guid ID of data object to be inserted or updated
1420 5211 jones
     * @throws IOException
1421
     */
1422 5319 jones
    private void putObject(String guid, String action) {
1423
        logMetacat.debug("Entering putObject: " + guid + "/" + action);
1424
        OutputStream out = null;
1425 5642 berkley
        Hashtable<String, File> parts = null;
1426 5319 jones
        try {
1427
            out = response.getOutputStream();
1428 5515 berkley
            response.setStatus(200);
1429 5450 berkley
            response.setContentType("text/xml");
1430 5319 jones
        } catch (IOException e1) {
1431
            logMetacat.error("Could not get the output stream for writing in putObject");
1432
        }
1433
        try {
1434 5353 berkley
1435
            // Read the incoming data from its Mime Multipart encoding
1436
            logMetacat.debug("Disassembling MIME multipart form");
1437
            InputStream object = null;
1438
            InputStream sysmeta = null;
1439 5394 berkley
1440 5638 berkley
            try
1441
            {
1442 5670 berkley
                //String req = IOUtils.toString(request.getInputStream());
1443
                //System.out.println("request: " + req);
1444
                //InputStream reqStr = IOUtils.toInputStream(req);
1445
                InputStream reqStr = request.getInputStream();
1446
                parts = processMMP(reqStr);
1447 5638 berkley
                object = new FileInputStream(parts.get("object"));
1448
                sysmeta = new FileInputStream(parts.get("sysmeta"));
1449 5670 berkley
1450 5674 berkley
                /*String obj = IOUtils.toString(object);
1451 5670 berkley
                String sm = IOUtils.toString(sysmeta);
1452
                System.out.println("object: " + obj);
1453
                System.out.println("sm: " + sm);
1454
                object = IOUtils.toInputStream(obj);
1455 5674 berkley
                sysmeta = IOUtils.toInputStream(sm);*/
1456
1457 5638 berkley
            }
1458
            catch(IOException ioe)
1459
            {
1460
                throw new ServiceFailure("1202",
1461
                        "IOException when processing Mime Multipart: " + ioe.getMessage());
1462
            }
1463 5616 berkley
1464 5353 berkley
            if ( action.equals(FUNCTION_NAME_INSERT)) { //handle inserts
1465 5211 jones
1466 5319 jones
                // Check if the objectId exists
1467
                IdentifierManager im = IdentifierManager.getInstance();
1468
                if (im.identifierExists(guid)) {
1469 5356 berkley
                    throw new IdentifierNotUnique("1000", "Identifier is already in use: " + guid);
1470 5319 jones
                }
1471 5211 jones
1472 5376 berkley
                logMetacat.debug("Commence creation...");
1473
                IBindingFactory bfact =
1474
                    BindingDirectory.getFactory(SystemMetadata.class);
1475
                IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
1476
                SystemMetadata m = (SystemMetadata) uctx.unmarshalDocument(sysmeta, null);
1477
1478
                CrudService cs = CrudService.getInstance();
1479 5386 berkley
                AuthToken token = new AuthToken(sessionId);
1480 5376 berkley
                cs.setParamsFromRequest(request);
1481
                Identifier id = new Identifier();
1482
                id.setValue(guid);
1483 5674 berkley
                Identifier rId = cs.create(token, id, object, m);
1484
                serializeServiceType(Identifier.class, rId, out);
1485 5386 berkley
1486 5353 berkley
            } else if (action.equals(FUNCTION_NAME_UPDATE)) { //handle updates
1487
                IdentifierManager im = IdentifierManager.getInstance();
1488
                CrudService cs = CrudService.getInstance();
1489
                Identifier obsoletedGuid = new Identifier();
1490
                Identifier id = new Identifier();
1491
                id.setValue(guid);
1492 5386 berkley
                AuthToken token = new AuthToken(sessionId);
1493 5353 berkley
1494
                //do some checks
1495
                if(params.get("obsoletedGuid") == null)
1496
                {
1497 5356 berkley
                    throw new InvalidRequest("1202", "obsoletedGuid must be contained in the request parameters.");
1498 5353 berkley
                }
1499
                //get the obsoletedGuid
1500
                String[] obsGuidS = params.get("obsoletedGuid");
1501
                obsoletedGuid.setValue(obsGuidS[0]);
1502
1503
                if (!im.identifierExists(obsoletedGuid.getValue()))
1504
                {
1505 5356 berkley
                    throw new InvalidRequest("1202", "The guid you are trying to update does not exist.");
1506 5353 berkley
                }
1507
1508
1509
                logMetacat.debug("Commence update...");
1510
1511
                //get the systemmetadata
1512
                IBindingFactory bfact =
1513
                        BindingDirectory.getFactory(SystemMetadata.class);
1514
                    IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
1515
                    SystemMetadata m = (SystemMetadata) uctx.unmarshalDocument(sysmeta, null);
1516
1517
                //do the update
1518
                try
1519
                {
1520
                    cs.setParamsFromRequest(request);
1521
                    Identifier rId = cs.update(token, id, object, obsoletedGuid, m);
1522 5674 berkley
                    serializeServiceType(Identifier.class, rId, out);
1523 5353 berkley
                }
1524
                catch(NotFound e)
1525
                {
1526 5356 berkley
                    throw new InvalidRequest("1202", "The guid you are trying to update does not exist.");
1527 5353 berkley
                }
1528
1529 5211 jones
            } else {
1530 5356 berkley
                throw new InvalidRequest("1000", "Operation must be create or update.");
1531 5211 jones
            }
1532 5638 berkley
1533
            //clean up the MMP files
1534 5674 berkley
            parts.get("sysmeta").delete();
1535
            parts.get("object").delete();
1536 5319 jones
        } catch (NotAuthorized e) {
1537 5617 berkley
            response.setStatus(500);
1538 5319 jones
            serializeException(e, out);
1539
        } catch (InvalidToken e) {
1540 5617 berkley
            response.setStatus(500);
1541 5319 jones
            serializeException(e, out);
1542
        } catch (ServiceFailure e) {
1543 5617 berkley
            response.setStatus(500);
1544 5319 jones
            serializeException(e, out);
1545
        } catch (IdentifierNotUnique e) {
1546 5617 berkley
            response.setStatus(500);
1547 5319 jones
            serializeException(e, out);
1548
        } catch (UnsupportedType e) {
1549 5617 berkley
            response.setStatus(500);
1550 5319 jones
            serializeException(e, out);
1551
        } catch (InsufficientResources e) {
1552 5617 berkley
            response.setStatus(500);
1553 5319 jones
            serializeException(e, out);
1554
        } catch (InvalidSystemMetadata e) {
1555 5617 berkley
            response.setStatus(500);
1556 5319 jones
            serializeException(e, out);
1557
        } catch (NotImplemented e) {
1558 5617 berkley
            response.setStatus(500);
1559 5319 jones
            serializeException(e, out);
1560
        } catch (InvalidRequest e) {
1561 5617 berkley
            response.setStatus(500);
1562 5319 jones
            serializeException(e, out);
1563 5394 berkley
        } /*catch (MessagingException e) {
1564 5356 berkley
            ServiceFailure sf = new ServiceFailure("1000", e.getMessage());
1565 5319 jones
            serializeException(sf, out);
1566 5636 berkley
        } catch (IOException e) {
1567 5617 berkley
            response.setStatus(500);
1568 5356 berkley
            ServiceFailure sf = new ServiceFailure("1000", e.getMessage());
1569 5319 jones
            serializeException(sf, out);
1570 5636 berkley
        }*/ catch (JiBXException e) {
1571 5617 berkley
            response.setStatus(500);
1572 5320 jones
            e.printStackTrace(System.out);
1573 5356 berkley
            InvalidSystemMetadata ism = new InvalidSystemMetadata("1080", e.getMessage());
1574 5320 jones
            serializeException(ism, out);
1575 5211 jones
        }
1576 5642 berkley
        finally
1577
        {
1578
            if(parts != null)
1579
            {
1580 5674 berkley
                parts.get("sysmeta").delete();
1581
                parts.get("object").delete();
1582 5642 berkley
            }
1583
        }
1584 5211 jones
    }
1585
1586
    /**
1587 5657 berkley
     * Handle delete
1588 5287 jones
     * @param guid ID of data object to be deleted
1589 5211 jones
     * @throws IOException
1590
     */
1591 5287 jones
    private void deleteObject(String guid) throws IOException
1592
    {
1593
        // Look up the localId for this global identifier
1594 5657 berkley
        System.out.println("!!!!!!!!!!!!!!!!!deleting object " + guid);
1595 5287 jones
        IdentifierManager im = IdentifierManager.getInstance();
1596
        String localId = "";
1597 5657 berkley
        OutputStream out = response.getOutputStream();
1598
        response.setStatus(200);
1599 5287 jones
        try {
1600
            localId = im.getLocalId(guid);
1601
        } catch (McdbDocNotFoundException e) {
1602 5657 berkley
            NotFound nf = new NotFound("1340", "Document with guid " + guid + " not found.");
1603
            response.setStatus(404);
1604
            serializeException(nf, out);
1605 5287 jones
        }
1606 5657 berkley
1607
        AuthToken token = new AuthToken(sessionId);
1608
        CrudService cs = CrudService.getInstance();
1609
        Identifier id = new Identifier();
1610
        id.setValue(guid);
1611
        try
1612
        {
1613
            System.out.println("Calling delete");
1614
            cs.delete(token, id);
1615 5673 berkley
            serializeServiceType(Identifier.class, id, out);
1616 5657 berkley
        }
1617
        catch (NotAuthorized e) {
1618
            response.setStatus(500);
1619
            serializeException(e, out);
1620
        } catch (InvalidToken e) {
1621
            response.setStatus(500);
1622
            serializeException(e, out);
1623
        } catch (ServiceFailure e) {
1624
            response.setStatus(500);
1625
            serializeException(e, out);
1626
        } catch (NotImplemented e) {
1627
            response.setStatus(500);
1628
            serializeException(e, out);
1629
        } catch (InvalidRequest e) {
1630
            response.setStatus(500);
1631
            serializeException(e, out);
1632
        } catch(NotFound e) {
1633
            response.setStatus(500);
1634
            serializeException(e, out);
1635 5673 berkley
        } catch(JiBXException e) {
1636
            response.setStatus(500);
1637
            serializeException(new ServiceFailure("1350", "JiBXException: " + e.getMessage()), out);
1638 5657 berkley
        }
1639 5211 jones
        out.close();
1640
    }
1641 5370 berkley
1642
    /**
1643
     * set the access perms on a document
1644
     * @throws IOException
1645
     */
1646 5424 berkley
    private void setaccess() throws Exception
1647 5370 berkley
    {
1648
        try
1649
        {
1650
            String guid = params.get("guid")[0];
1651
            Identifier id = new Identifier();
1652
            id.setValue(guid);
1653
            AuthToken token = new AuthToken(sessionId);
1654
            String principal = params.get("principal")[0];
1655
            String permission = params.get("permission")[0];
1656
            String permissionType = params.get("permissionType")[0];
1657
            String permissionOrder = params.get("permissionOrder")[0];
1658
            String setSystemMetadata = params.get("setsystemmetadata")[0];
1659 5424 berkley
            boolean ssm = false;
1660 5370 berkley
            if(setSystemMetadata.equals("true") || setSystemMetadata.equals("TRUE") ||
1661 5424 berkley
                    setSystemMetadata.equals("yes"))
1662
            {
1663
                ssm = true;
1664 5370 berkley
            }
1665 5424 berkley
            CrudService cs = CrudService.getInstance();
1666 5484 berkley
            //TODO: remove the setsystemmetadata param and set this so the systemmetadata always gets set
1667 5424 berkley
            cs.setAccess(token, id, principal, permission, permissionType, permissionOrder, ssm);
1668 5370 berkley
        }
1669
        catch(Exception e)
1670
        {
1671 5512 berkley
            response.setStatus(500);
1672 5370 berkley
            printError("Error setting access in ResourceHandler: " + e.getMessage(), response);
1673 5424 berkley
            throw e;
1674 5370 berkley
        }
1675
    }
1676 5211 jones
1677
    /**
1678
     * Earthgrid API > Authentication Service > Login Function : calls MetacatHandler > handleLoginAction
1679
     *
1680
     * @throws IOException
1681
     */
1682
    private void login() throws IOException {
1683
        PrintWriter out = response.getWriter();
1684 5515 berkley
        response.setStatus(200);
1685 5450 berkley
        response.setContentType("text/xml");
1686 5211 jones
        handler.handleLoginAction(out, params, request, response);
1687
        out.close();
1688
    }
1689
1690
    /**
1691
     * Earthgrid API > Authentication Service > Logout Function : calls MetacatHandler > handleLogoutAction
1692
     *
1693
     * @throws IOException
1694
     */
1695
    private void logout() throws IOException {
1696
        PrintWriter out = response.getWriter();
1697 5515 berkley
        response.setStatus(200);
1698 5450 berkley
        response.setContentType("text/xml");
1699 5211 jones
        handler.handleLogoutAction(out, params, request, response);
1700
        out.close();
1701
    }
1702
1703
    /**
1704
     * Prints xml response
1705
     * @param message Message to be displayed
1706
     * @param response Servlet response that xml message will be printed
1707
     * */
1708
    private void printError(String message, HttpServletResponse response) {
1709
        try {
1710 5512 berkley
            logMetacat.error("ResourceHandler: Printing error to servlet response: " + message);
1711 5211 jones
            PrintWriter out = response.getWriter();
1712
            response.setContentType("text/xml");
1713
            out.println("<?xml version=\"1.0\"?>");
1714
            out.println("<error>");
1715
            out.println(message);
1716
            out.println("</error>");
1717
            out.close();
1718
        } catch (IOException e) {
1719
            e.printStackTrace();
1720
        }
1721
    }
1722 5370 berkley
1723 5319 jones
    private void serializeException(BaseException e, OutputStream out) {
1724
        // TODO: Use content negotiation to determine which return format to use
1725
        response.setContentType("text/xml");
1726
        response.setStatus(e.getCode());
1727 5512 berkley
1728
        logMetacat.error("ResourceHandler: Serializing exception with code " + e.getCode() + ": " + e.getMessage());
1729
        e.printStackTrace();
1730
1731 5319 jones
        try {
1732
            IOUtils.write(e.serialize(BaseException.FMT_XML), out);
1733
        } catch (IOException e1) {
1734
            logMetacat.error("Error writing exception to stream. "
1735
                    + e1.getMessage());
1736
        }
1737
    }
1738
1739 5211 jones
}