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.IOException;
26
import java.io.InputStream;
27
import java.io.OutputStream;
28
import java.io.PrintWriter;
29
import java.util.Enumeration;
30
import java.util.Hashtable;
31
import java.util.Timer;
32

    
33
import javax.mail.BodyPart;
34
import javax.mail.MessagingException;
35
import javax.mail.internet.MimeMultipart;
36
import javax.servlet.ServletContext;
37
import javax.servlet.http.HttpServletRequest;
38
import javax.servlet.http.HttpServletResponse;
39

    
40
import org.apache.commons.io.IOUtils;
41
import org.apache.log4j.Logger;
42
import org.dataone.service.exceptions.BaseException;
43
import org.dataone.service.exceptions.IdentifierNotUnique;
44
import org.dataone.service.exceptions.InsufficientResources;
45
import org.dataone.service.exceptions.InvalidRequest;
46
import org.dataone.service.exceptions.InvalidSystemMetadata;
47
import org.dataone.service.exceptions.InvalidToken;
48
import org.dataone.service.exceptions.NotAuthorized;
49
import org.dataone.service.exceptions.NotImplemented;
50
import org.dataone.service.exceptions.ServiceFailure;
51
import org.dataone.service.exceptions.UnsupportedType;
52
import org.dataone.service.types.AuthToken;
53
import org.dataone.service.types.Identifier;
54
import org.dataone.service.types.SystemMetadata;
55
import org.jibx.runtime.BindingDirectory;
56
import org.jibx.runtime.IBindingFactory;
57
import org.jibx.runtime.IUnmarshallingContext;
58
import org.jibx.runtime.JiBXException;
59

    
60
import edu.ucsb.nceas.metacat.DBUtil;
61
import edu.ucsb.nceas.metacat.IdentifierManager;
62
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
63
import edu.ucsb.nceas.metacat.MetacatHandler;
64
import edu.ucsb.nceas.metacat.dataone.CrudService;
65
import edu.ucsb.nceas.metacat.util.RequestUtil;
66
import edu.ucsb.nceas.metacat.util.SessionData;
67

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

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

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

    
180
    /**HTTP Verb GET*/
181
    public static final byte GET = 1;
182
    /**HTTP Verb POST*/
183
    public static final byte POST = 2;
184
    /**HTTP Verb PUT*/
185
    public static final byte PUT = 3;
186
    /**HTTP Verb DELETE*/
187
    public static final byte DELETE = 4;
188

    
189
    /*
190
     * API Resources
191
     */
192
    private static final String RESOURCE_OBJECTS = "object";
193
    private static final String RESOURCE_SESSION = "session";
194
    private static final String RESOURCE_IDENTIFIER = "identifier";
195

    
196
    /*
197
     * API Functions used as URL parameters
198
     */
199
    private static final String FUNCTION_KEYWORD = "op";
200
    private static final String FUNCTION_NAME_LOGIN = "login";
201
    private static final String FUNCTION_NAME_LOGOUT = "logout";
202
    private static final String FUNCTION_NAME_ISREGISTERED = "isregistered";
203
    private static final String FUNCTION_NAME_GETALLDOCS = "getalldocids";
204
    private static final String FUNCTION_NAME_GETNEXTREV = "getnextrevision";
205
    private static final String FUNCTION_NAME_GETNEXTOBJ = "getnextobject";
206
    private static final String FUNCTION_NAME_INSERT = "insert";
207
    private static final String FUNCTION_NAME_UPDATE = "update";
208

    
209
    private ServletContext servletContext;
210
    private Logger logMetacat;
211
    private MetacatHandler handler;
212
    private HttpServletRequest request;
213
    private HttpServletResponse response;
214
    private String username;
215
    private String password;
216
    private String sessionId;
217
    private String[] groupNames;
218

    
219
    private Hashtable<String, String[]> params;
220

    
221
    /**Initializes new instance by setting servlet context,request and response*/
222
    public ResourceHandler(ServletContext servletContext,
223
            HttpServletRequest request, HttpServletResponse response) {
224
        this.servletContext = servletContext;
225
        this.request = request;
226
        this.response = response;
227
    }
228

    
229
    /**
230
     *  copies request parameters to a hashtable which is given as argument to native metacathandler functions  
231
     */
232
    private void initParams() {
233

    
234
        String name = null;
235
        String[] value = null;
236
        Enumeration paramlist = request.getParameterNames();
237
        while (paramlist.hasMoreElements()) {
238
            name = (String) paramlist.nextElement();
239
            value = request.getParameterValues(name);
240
            params.put(name, value);
241
        }
242

    
243
    }
244

    
245
    /**
246
     * 
247
     * Load user details of metacat session from the request 
248
     * 
249
     */
250
    private void loadSessionData() {
251
        SessionData sessionData = RequestUtil.getSessionData(request);
252

    
253
        // TODO: validate the session before allowing these values to be set
254
        username = sessionData.getUserName();
255
        password = sessionData.getPassword();
256
        groupNames = sessionData.getGroupNames();
257
        sessionId = sessionData.getId();
258

    
259
        if (username == null) {
260
            username = "public";
261
        }
262
    }
263

    
264
    /**
265
     * This function is called from REST APU servlet and handles each request to the servlet 
266
     * 
267
     * @param httpVerb (GET, POST, PUT or DELETE)
268
     */
269
    public void handle(byte httpVerb) {
270

    
271
        logMetacat = Logger.getLogger(ResourceHandler.class);
272
        try {
273
            String resource = request.getServletPath();
274

    
275
            boolean status = false;
276

    
277
            if (resource != null) {
278
                resource = request.getServletPath().substring(1);
279
                System.out.println("accessing resource: " + resource);
280

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

    
284
                Timer timer = new Timer();
285
                handler = new MetacatHandler(servletContext, timer);
286

    
287
                if (resource.equals(RESOURCE_SESSION) && httpVerb == POST
288
                        && params.get(FUNCTION_KEYWORD) != null) {
289
                    if (params.get(FUNCTION_KEYWORD)[0]
290
                            .equals(FUNCTION_NAME_LOGIN)) {
291
                        login();
292
                        status = true;
293
                    } else if (params.get(FUNCTION_KEYWORD)[0]
294
                            .equals(FUNCTION_NAME_LOGOUT)) {
295
                        logout();
296
                        status = true;
297
                    }
298
                } else if (resource.equals(RESOURCE_OBJECTS)) {
299
                    logMetacat.debug("D1 Rest: Starting resource processing...");
300
                    loadSessionData();
301

    
302
                    String objectId = request.getPathInfo();
303
                    if (objectId != null && objectId.length() > 1)
304
                        objectId = request.getPathInfo().substring(1); //trim the slash
305
                    logMetacat.debug("Processing objectId: " + objectId);
306
                    logMetacat.debug("verb:" + httpVerb);
307

    
308
                    logMetacat.debug("objectId:" + objectId);
309

    
310
                    if (httpVerb == GET) {
311
                        getObject(objectId);
312
                        status = true;
313
                    } else if (httpVerb == POST) {
314
                        putObject(objectId, FUNCTION_NAME_INSERT);
315
                        status = true;
316
                    } else if (httpVerb == PUT) {
317
                        putObject(objectId, FUNCTION_NAME_UPDATE);
318
                        status = true;
319
                    } else if (httpVerb == DELETE) {
320
                        deleteObject(objectId);
321
                        status = true;
322
                    }
323

    
324
                } else if (resource.equals(RESOURCE_IDENTIFIER)) {
325

    
326
                    String identifierId = request.getPathInfo();
327
                    if (identifierId != null && identifierId.length() > 1)
328
                        identifierId = request.getPathInfo().substring(1); //trim the slash
329

    
330
                    System.out.println("identifierId:" + identifierId);
331

    
332
                    if (httpVerb == GET) {
333
                        String op = params.get(FUNCTION_KEYWORD)[0];
334
                        System.out.println("op:" + op);
335
                        if (op.equals(FUNCTION_NAME_ISREGISTERED)) {
336
                            isRegistered(identifierId);
337
                            status = true;
338
                        } else if (op.equals(FUNCTION_NAME_GETALLDOCS)) {
339
                            getAllDocIds();
340
                            status = true;
341
                        } else if (op.equals(FUNCTION_NAME_GETNEXTREV)) {
342
                            getNextRevision(identifierId);
343
                            status = true;
344
                        } else if (op.equals(FUNCTION_NAME_GETNEXTOBJ)) {
345
                            getNextObject();
346
                            status = true;
347
                        }
348

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

    
358
                }
359
                if (!status)
360
                    printError("Incorrect parameters!", response);
361
            } else {
362
                printError("Incorrect resource!", response);
363
            }
364
        } catch (Exception e) {
365
            logMetacat.error(e.getMessage());
366
            e.printStackTrace();
367
        }
368
    }
369

    
370
    /**
371
     *  Earthgrid API > Identifier Service > isRegistered Function : calls MetacatHandler > handleIdIsRegisteredAction
372
     * @param guid
373
     * @throws IOException
374
     */
375
    private void isRegistered(String guid) throws IOException
376
    {
377
        
378
        // Look up the localId for this guid
379
        IdentifierManager im = IdentifierManager.getInstance();
380
        String localId = "";
381
        try {
382
            localId = im.getLocalId(guid);
383
        } catch (McdbDocNotFoundException e) {
384
            // TODO: Need to return the proper DataONE exception
385
        }
386
        
387
        params.put("docid", new String[] { localId });
388
        PrintWriter out = response.getWriter();
389
        handler.handleIdIsRegisteredAction(out, params, response);
390
        out.close();
391
    }
392

    
393
    /**
394
     * Earthgrid API > Identifier Service > getAllDocIds Function : calls MetacatHandler > handleGetAllDocidsAction
395
     * @throws IOException
396
     */
397
    private void getAllDocIds() throws IOException {
398
        PrintWriter out = response.getWriter();
399
        handler.handleGetAllDocidsAction(out, params, response);
400
        out.close();
401
    }
402

    
403
    /**
404
     * Earthgrid API > Identifier Service > getNextRevision Function : calls MetacatHandler > handleGetRevisionAndDocTypeAction
405
     * @param guid
406
     * @throws IOException
407
     */
408
    private void getNextRevision(String guid) throws IOException 
409
    {
410
        params.put("docid", new String[] { guid });
411
        PrintWriter out = response.getWriter();
412
        //handler.handleGetRevisionAndDocTypeAction(out, params);
413

    
414
        try {
415
            // Make sure there is a docid
416
            if (guid == null || guid.equals("")) {
417
                throw new Exception("User didn't specify docid!");
418
            }
419

    
420
            // Look up the localId for this guid
421
            IdentifierManager im = IdentifierManager.getInstance();
422
            String localId = "";
423
            try {
424
                localId = im.getLocalId(guid);
425
            } catch (McdbDocNotFoundException e) {
426
                // TODO: Need to return the proper DataONE exception
427
            }
428
           
429
            // Create a DBUtil object
430
            DBUtil dbutil = new DBUtil();
431
            // Get a rev and doctype
432
            String revAndDocType = dbutil
433
                    .getCurrentRevisionAndDocTypeForGivenDocument(localId);
434
            int revision = Integer.parseInt(revAndDocType.split(";")[0]) + 1;
435

    
436
            out.println("<?xml version=\"1.0\"?>");
437
            out.print("<next-revision>");
438
            out.print(revision);
439
            out.print("</next-revision>");
440

    
441
        } catch (Exception e) {
442
            // Handle exception
443
            out.println("<?xml version=\"1.0\"?>");
444
            out.println("<error>");
445
            out.println(e.getMessage());
446
            out.println("</error>");
447
        }
448

    
449
        out.close();
450
    }
451

    
452
    /**
453
     * Earthgrid API > Identifier Service > getNextObject Function : calls MetacatHandler > handleGetMaxDocidAction
454
     * @throws IOException
455
     */
456
    private void getNextObject() throws IOException {
457
        PrintWriter out = response.getWriter();
458
        handler.handleGetMaxDocidAction(out, params, response);
459
        out.close();
460
    }
461

    
462
    /**
463
     * Implements REST version of DataONE CRUD API --> get
464
     * @param guid ID of data object to be read
465
     */
466
    private void getObject(String guid) {
467
        CrudService cs = new CrudService(servletContext, request, response);
468
        AuthToken token = null;
469
        OutputStream out = null;
470
        try {
471
            out = response.getOutputStream();
472
            Identifier id = new Identifier();
473
            id.setValue(guid);
474
            InputStream data = cs.get(token, id);
475
            IOUtils.copyLarge(data, response.getOutputStream());
476
        } catch (BaseException e) {
477
                serializeException(e, out);
478
        } catch (IOException e) {
479
            ServiceFailure sf = new ServiceFailure(1030, e.getMessage());
480
            serializeException(sf, out);
481
        }
482
    }
483

    
484
    /**
485
     * Earthgrid API > Query Service > Query Function : translates ecogrid query document to metacat query 
486
     * then calls DBQuery > createResultDocument function and then again translate resultset to ecogrid resultset
487
     * 
488
     * NOTE:
489
     *      This is the only method that uses EcoGrid classes for its implementation.  
490
     *      It does so because it takes an EcoGrid Query as input, and outputs an
491
     *      EcoGrid ResultSet document.  These documents are parsed by the auto-generated
492
     *      EcoGrid classes from axis, and so we link to them here rather than re-inventing them.
493
     *      This creates a circular dependency, because the Metacat classes are needed
494
     *      to build the EcoGrid implementation, and the EcoGrid jars are needed to build this query()
495
     *      method.  This circularity could be resolved by moving the EcoGrid classes
496
     *      to Metacat directly.  As we transition away from EcoGrid SOAP methods in
497
     *      favor of these REST interfaces, this circular dependency can be eliminated.
498
     *        
499
     * @throws Exception
500
     */
501
    private void query() throws Exception {
502
        /*  This block commented out because of the EcoGrid circular dependency.
503
         *  For now, query will not be supported until the circularity can be
504
         *  resolved, probably by moving the ecogrid query syntax transformers
505
         *  directly into the Metacat codebase.  MBJ 2010-02-03
506
         
507
        try {
508
            EcogridQueryParser parser = new EcogridQueryParser(request
509
                    .getReader());
510
            parser.parseXML();
511
            QueryType queryType = parser.getEcogridQuery();
512
            EcogridJavaToMetacatJavaQueryTransformer queryTransformer = 
513
                new EcogridJavaToMetacatJavaQueryTransformer();
514
            QuerySpecification metacatQuery = queryTransformer
515
                    .transform(queryType);
516

    
517
            DBQuery metacat = new DBQuery();
518

    
519
            boolean useXMLIndex = (new Boolean(PropertyService
520
                    .getProperty("database.usexmlindex"))).booleanValue();
521
            String xmlquery = "query"; // we don't care the query in resultset,
522
            // the query can be anything
523
            PrintWriter out = null; // we don't want metacat result, so set out null
524

    
525
            // parameter: queryspecification, user, group, usingIndexOrNot
526
            StringBuffer result = metacat.createResultDocument(xmlquery,
527
                    metacatQuery, out, username, groupNames, useXMLIndex);
528

    
529
            // create result set transfer		
530
            String saxparser = PropertyService.getProperty("xml.saxparser");
531
            MetacatResultsetParser metacatResultsetParser = new MetacatResultsetParser(
532
                    new StringReader(result.toString()), saxparser, queryType
533
                            .getNamespace().get_value());
534
            ResultsetType records = metacatResultsetParser.getEcogridResult();
535

    
536
            System.out
537
                    .println(EcogridResultsetTransformer.toXMLString(records));
538
            response.setContentType("text/xml");
539
            out = response.getWriter();
540
            out.print(EcogridResultsetTransformer.toXMLString(records));
541

    
542
        } catch (Exception e) {
543
            e.printStackTrace();
544
        }*/
545
        response.setContentType("text/xml");
546
        PrintWriter out = response.getWriter();
547
        out.print("<error>Query operation not yet supported by Metacat.</error>");
548
        out.close();
549
    }
550
    
551
    /**
552
     * Earthgrid API > Put Service >Put Function : calls MetacatHandler > handleInsertOrUpdateAction 
553
     * 
554
     * @param guid ID of data object to be inserted or updated
555
     * @throws IOException
556
     */
557
    private void putObject(String guid, String action) {
558
        logMetacat.debug("Entering putObject: " + guid + "/" + action);
559
        
560
        // TODO: This function lacks proper handling of authz and authn, so it
561
        // seems that anyone can insert or update; interacts with 
562
        // loadSessionData(), which doesn't validate the session
563
        
564
        // Get an output stream for handling errors; this should really be passed in as
565
        // a parameter
566
        OutputStream out = null;
567
        try {
568
            out = response.getOutputStream();
569
        } catch (IOException e1) {
570
            logMetacat.error("Could not get the output stream for writing in putObject");
571
        }
572
        try {
573
            if (action.equals(FUNCTION_NAME_UPDATE)
574
                    || action.equals(FUNCTION_NAME_INSERT)) {
575

    
576
                // Check if the objectId exists
577
                IdentifierManager im = IdentifierManager.getInstance();
578
                if (im.identifierExists(guid)) {
579
                    throw new IdentifierNotUnique(1000, "Identifier is already in use: " + guid);
580
                }
581

    
582
                // TODO: For updates, need to check if the old id exists, and if not throw an exception
583

    
584
                // Read the incoming data from its Mime Multipart encoding
585
                logMetacat.debug("Disassembling MIME multipart form");
586
                InputStream object = null;
587
                InputStream sysmeta = null;
588
                MimeMultipart mmp = new MimeMultipart(new InputStreamDataSource("message", request.getInputStream()));
589
                logMetacat.debug("MMP created.");
590
                mmp.writeTo(System.out);
591
                for (int i = 0; i < mmp.getCount(); i++) {
592
                    logMetacat.debug("Looping over MMP parts: " + i);
593
                    BodyPart part = mmp.getBodyPart(i);
594
                    String name = part.getFileName();
595
                    logMetacat.debug("Part name is: " + name);
596
                    logMetacat.debug("Part has class name: " + part.getClass().getName());
597
                    if (name.equals("object")) {
598
                        object = part.getInputStream();
599
                        logMetacat.debug("Found object part, size is: " + part.getSize());
600
                    } else if (name.equals("systemmetadata")) {
601
                        sysmeta = part.getInputStream();
602
                        logMetacat.debug("Found sysmeta part, size is: " + part.getSize());
603
                    } else {
604
                        throw new InvalidRequest(1000, "Request had malformed MIME part with name: " + name);
605
                    }
606
                }
607

    
608
                // TODO: access control -- should be in CrudService et al. I think
609
                //if (username != null && !username.equals("public")) {
610
                if (username != null) {
611

    
612
                    logMetacat.debug("Commence creation...");
613
                    AuthToken token = null;
614
                    IBindingFactory bfact =
615
                        BindingDirectory.getFactory(SystemMetadata.class);
616
                    IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
617
                    SystemMetadata m = (SystemMetadata) uctx.unmarshalDocument(sysmeta, null);
618

    
619
                    CrudService cs = new CrudService(servletContext, request, response);
620
                    Identifier id = new Identifier();
621
                    id.setValue(guid);
622
                    cs.create(token, id, object, m);
623

    
624
                } else {
625
                    logMetacat.debug("Unauthorized to create.");
626
                    throw new NotAuthorized(1000, "Permission denied for user " + username);
627
                }
628
            } else {
629
                throw new InvalidRequest(1000, "Operation must be create or update.");
630
            }
631
        } catch (NotAuthorized e) {
632
            serializeException(e, out);
633
        } catch (InvalidToken e) {
634
            serializeException(e, out);
635
        } catch (ServiceFailure e) {
636
            serializeException(e, out);
637
        } catch (IdentifierNotUnique e) {
638
            serializeException(e, out);
639
        } catch (UnsupportedType e) {
640
            serializeException(e, out);
641
        } catch (InsufficientResources e) {
642
            serializeException(e, out);
643
        } catch (InvalidSystemMetadata e) {
644
            serializeException(e, out);
645
        } catch (NotImplemented e) {
646
            serializeException(e, out);
647
        } catch (InvalidRequest e) {
648
            serializeException(e, out);
649
        } catch (MessagingException e) {
650
            ServiceFailure sf = new ServiceFailure(1000, e.getMessage());
651
            serializeException(sf, out);
652
        } catch (IOException e) {
653
            ServiceFailure sf = new ServiceFailure(1000, e.getMessage());
654
            serializeException(sf, out);
655
        } catch (JiBXException e) {
656
            e.printStackTrace(System.out);
657
            InvalidSystemMetadata ism = new InvalidSystemMetadata(1080, e.getMessage());
658
            serializeException(ism, out);
659
        }
660
    }
661

    
662
    /**
663
     * Earthgrid API > Put Service > Delete Function : calls MetacatHandler > handleDeleteAction  
664
     * 
665
     * @param guid ID of data object to be deleted
666
     * @throws IOException
667
     */
668
    private void deleteObject(String guid) throws IOException 
669
    {
670
        // Look up the localId for this global identifier
671
        IdentifierManager im = IdentifierManager.getInstance();
672
        String localId = "";
673
        try {
674
            localId = im.getLocalId(guid);
675
        } catch (McdbDocNotFoundException e) {
676
            // TODO: Need to return the proper DataONE exception
677
        }
678
        
679
        params.put("docid", new String[] { localId });
680
        PrintWriter out = response.getWriter();
681
        handler.handleDeleteAction(out, params, request, response, username,
682
                groupNames);
683
        out.close();
684
    }
685

    
686
    /**
687
     * Earthgrid API > Authentication Service > Login Function : calls MetacatHandler > handleLoginAction
688
     * 
689
     * @throws IOException
690
     */
691
    private void login() throws IOException {
692
        PrintWriter out = response.getWriter();
693
        handler.handleLoginAction(out, params, request, response);
694
        out.close();
695
    }
696

    
697
    /**
698
     * Earthgrid API > Authentication Service > Logout Function : calls MetacatHandler > handleLogoutAction
699
     * 
700
     * @throws IOException
701
     */
702
    private void logout() throws IOException {
703
        PrintWriter out = response.getWriter();
704
        handler.handleLogoutAction(out, params, request, response);
705
        out.close();
706
    }
707

    
708
    /**
709
     * Prints xml response
710
     * @param message Message to be displayed
711
     * @param response Servlet response that xml message will be printed 
712
     * */
713
    private void printError(String message, HttpServletResponse response) {
714
        try {
715
            PrintWriter out = response.getWriter();
716
            response.setContentType("text/xml");
717
            out.println("<?xml version=\"1.0\"?>");
718
            out.println("<error>");
719
            out.println(message);
720
            out.println("</error>");
721
            out.close();
722
        } catch (IOException e) {
723
            e.printStackTrace();
724
        }
725
    }
726

    
727
    private void serializeException(BaseException e, OutputStream out) {
728
        // TODO: Use content negotiation to determine which return format to use
729
        response.setContentType("text/xml");
730
        response.setStatus(e.getCode());
731
        try {
732
            IOUtils.write(e.serialize(BaseException.FMT_XML), out);
733
        } catch (IOException e1) {
734
            logMetacat.error("Error writing exception to stream. " 
735
                    + e1.getMessage());
736
        }
737
    }
738

    
739
}
(2-2/3)