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

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

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

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

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

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

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

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

    
191
    /*
192
     * API Resources
193
     */
194
    private static final String RESOURCE_OBJECTS = "object";
195
    private static final String RESOURCE_META = "/meta";
196
    private static final String RESOURCE_SESSION = "session";
197
    private static final String RESOURCE_IDENTIFIER = "identifier";
198

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

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

    
222
    private Hashtable<String, String[]> params;
223

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

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

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

    
246
    }
247

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

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

    
262
        if (username == null) {
263
            username = "public";
264
        }
265
    }
266

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

    
274
        logMetacat = Logger.getLogger(ResourceHandler.class);
275
        try {
276
            String resource = request.getServletPath();
277

    
278
            boolean status = false;
279

    
280
            if (resource != null) {
281
                resource = request.getServletPath().substring(1);
282
                System.out.println("accessing resource: " + resource);
283

    
284
                params = new Hashtable<String, String[]>();
285
                initParams();
286

    
287
                Timer timer = new Timer();
288
                handler = new MetacatHandler(timer);
289

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

    
305
                    boolean isSysmetaRequest = false;
306
                    String objectId = request.getPathInfo();
307
                    if (objectId != null && objectId.length() > 1) {
308
                        objectId = request.getPathInfo().substring(1); //trim the slash
309
                        
310
                        // Check if this is a request for SystemMetadata
311
                        // TODO: Note that this REST uri means that GUIDs can not contain the RESOURCE_META string
312
                        int start = objectId.indexOf(RESOURCE_META);
313
                        if (start >= 0) {
314
                            logMetacat.debug("Pruning meta at start value: " + start);
315
                            objectId = objectId.substring(0, start);
316
                            logMetacat.debug("New objectId for meta is: " + objectId);
317
                            isSysmetaRequest = true;
318
                        }
319
                    }
320
                    logMetacat.debug("Processing objectId: " + objectId);
321
                    logMetacat.debug("verb:" + httpVerb);
322

    
323
                    logMetacat.debug("objectId:" + objectId);
324

    
325
                    if (httpVerb == GET) {
326
                        if (isSysmetaRequest) {
327
                            getSystemMetadataObject(objectId);
328
                        } else {
329
                            getObject(objectId);
330
                        }
331
                        status = true;
332
                    } else if (httpVerb == POST) {
333
                        putObject(objectId, FUNCTION_NAME_INSERT);
334
                        status = true;
335
                    } else if (httpVerb == PUT) {
336
                        putObject(objectId, FUNCTION_NAME_UPDATE);
337
                        status = true;
338
                    } else if (httpVerb == DELETE) {
339
                        deleteObject(objectId);
340
                        status = true;
341
                    }
342

    
343
                } else if (resource.equals(RESOURCE_IDENTIFIER)) {
344

    
345
                    String identifierId = request.getPathInfo();
346
                    if (identifierId != null && identifierId.length() > 1)
347
                        identifierId = request.getPathInfo().substring(1); //trim the slash
348

    
349
                    System.out.println("identifierId:" + identifierId);
350

    
351
                    if (httpVerb == GET) {
352
                        String op = params.get(FUNCTION_KEYWORD)[0];
353
                        System.out.println("op:" + op);
354
                        if (op.equals(FUNCTION_NAME_ISREGISTERED)) {
355
                            isRegistered(identifierId);
356
                            status = true;
357
                        } else if (op.equals(FUNCTION_NAME_GETALLDOCS)) {
358
                            getAllDocIds();
359
                            status = true;
360
                        } else if (op.equals(FUNCTION_NAME_GETNEXTREV)) {
361
                            getNextRevision(identifierId);
362
                            status = true;
363
                        } else if (op.equals(FUNCTION_NAME_GETNEXTOBJ)) {
364
                            getNextObject();
365
                            status = true;
366
                        }
367

    
368
                    } else if (httpVerb == PUT) {
369
                        //Earthgrid API > Identifier Service > addLSID Function 
370
                        printError(
371
                                "This method is not supported by metacat.  To "
372
                                        + "add a new LSID, add a document to metacat.",
373
                                response);
374
                        status = true;
375
                    }
376

    
377
                }
378
                if (!status)
379
                    printError("Incorrect parameters!", response);
380
            } else {
381
                printError("Incorrect resource!", response);
382
            }
383
        } catch (Exception e) {
384
            logMetacat.error(e.getMessage());
385
            e.printStackTrace();
386
        }
387
    }
388

    
389
    /**
390
     *  Earthgrid API > Identifier Service > isRegistered Function : calls MetacatHandler > handleIdIsRegisteredAction
391
     * @param guid
392
     * @throws IOException
393
     */
394
    private void isRegistered(String guid) throws IOException
395
    {
396
        
397
        // Look up the localId for this guid
398
        IdentifierManager im = IdentifierManager.getInstance();
399
        String localId = "";
400
        try {
401
            localId = im.getLocalId(guid);
402
        } catch (McdbDocNotFoundException e) {
403
            // TODO: Need to return the proper DataONE exception
404
        }
405
        
406
        params.put("docid", new String[] { localId });
407
        PrintWriter out = response.getWriter();
408
        handler.handleIdIsRegisteredAction(out, params, response);
409
        out.close();
410
    }
411

    
412
    /**
413
     * Earthgrid API > Identifier Service > getAllDocIds Function : calls MetacatHandler > handleGetAllDocidsAction
414
     * @throws IOException
415
     */
416
    private void getAllDocIds() throws IOException {
417
        PrintWriter out = response.getWriter();
418
        handler.handleGetAllDocidsAction(out, params, response);
419
        out.close();
420
    }
421

    
422
    /**
423
     * Earthgrid API > Identifier Service > getNextRevision Function : calls MetacatHandler > handleGetRevisionAndDocTypeAction
424
     * @param guid
425
     * @throws IOException
426
     */
427
    private void getNextRevision(String guid) throws IOException 
428
    {
429
        params.put("docid", new String[] { guid });
430
        PrintWriter out = response.getWriter();
431
        //handler.handleGetRevisionAndDocTypeAction(out, params);
432

    
433
        try {
434
            // Make sure there is a docid
435
            if (guid == null || guid.equals("")) {
436
                throw new Exception("User didn't specify docid!");
437
            }
438

    
439
            // Look up the localId for this guid
440
            IdentifierManager im = IdentifierManager.getInstance();
441
            String localId = "";
442
            try {
443
                localId = im.getLocalId(guid);
444
            } catch (McdbDocNotFoundException e) {
445
                // TODO: Need to return the proper DataONE exception
446
            }
447
           
448
            // Create a DBUtil object
449
            DBUtil dbutil = new DBUtil();
450
            // Get a rev and doctype
451
            String revAndDocType = dbutil
452
                    .getCurrentRevisionAndDocTypeForGivenDocument(localId);
453
            int revision = Integer.parseInt(revAndDocType.split(";")[0]) + 1;
454

    
455
            out.println("<?xml version=\"1.0\"?>");
456
            out.print("<next-revision>");
457
            out.print(revision);
458
            out.print("</next-revision>");
459

    
460
        } catch (Exception e) {
461
            // Handle exception
462
            out.println("<?xml version=\"1.0\"?>");
463
            out.println("<error>");
464
            out.println(e.getMessage());
465
            out.println("</error>");
466
        }
467

    
468
        out.close();
469
    }
470

    
471
    /**
472
     * Earthgrid API > Identifier Service > getNextObject Function : calls MetacatHandler > handleGetMaxDocidAction
473
     * @throws IOException
474
     */
475
    private void getNextObject() throws IOException {
476
        PrintWriter out = response.getWriter();
477
        handler.handleGetMaxDocidAction(out, params, response);
478
        out.close();
479
    }
480

    
481
    /**
482
     * Implements REST version of DataONE CRUD API --> get
483
     * @param guid ID of data object to be read
484
     */
485
    private void getObject(String guid) {
486
      //hack...fix this
487
        //CrudService cs = new CrudService(servletContext, request, response);
488
        CrudService cs = CrudService.getInstance();
489
        cs.setParamsFromRequest(request);
490
        AuthToken token = null;
491
        OutputStream out = null;
492
        try {
493
            out = response.getOutputStream();
494
            Identifier id = new Identifier();
495
            id.setValue(guid);
496
            InputStream data = cs.get(token, id);
497
            IOUtils.copyLarge(data, response.getOutputStream());
498
        } catch (BaseException e) {
499
                serializeException(e, out);
500
        } catch (IOException e) {
501
            ServiceFailure sf = new ServiceFailure(1030, e.getMessage());
502
            serializeException(sf, out);
503
        }
504
    }
505

    
506
    /**
507
     * Implements REST version of DataONE CRUD API --> getSystemMetadata
508
     * @param guid ID of data object to be read
509
     */
510
    private void getSystemMetadataObject(String guid) {
511
        //CrudService cs = new CrudService(servletContext, request, response);
512
        CrudService cs = CrudService.getInstance();
513
        cs.setParamsFromRequest(request);
514
        AuthToken token = null;
515
        OutputStream out = null;
516
        try {
517
            out = response.getOutputStream();
518
            Identifier id = new Identifier();
519
            id.setValue(guid);
520
            SystemMetadata sysmeta = cs.getSystemMetadata(token, id);
521
            logMetacat.debug("Got sysmeta for: " + sysmeta.getIdentifier().getValue());
522
            
523
            // Serialize and write it to the output stream
524
            try {
525
                IBindingFactory bfact = BindingDirectory.getFactory(SystemMetadata.class);
526
                IMarshallingContext mctx = bfact.createMarshallingContext();
527
                mctx.marshalDocument(sysmeta, "UTF-8", null, out);
528
            } catch (JiBXException e) {
529
                throw new ServiceFailure(1190, "Failed to serialize SystemMetadata: " + e.getMessage());
530
            }
531
        } catch (BaseException e) {
532
                serializeException(e, out);
533
        } catch (IOException e) {
534
            ServiceFailure sf = new ServiceFailure(1030, e.getMessage());
535
            serializeException(sf, out);
536
        } finally {
537
            IOUtils.closeQuietly(out);
538
        }
539
    }
540
    
541
    /**
542
     * Earthgrid API > Query Service > Query Function : translates ecogrid query document to metacat query 
543
     * then calls DBQuery > createResultDocument function and then again translate resultset to ecogrid resultset
544
     * 
545
     * NOTE:
546
     *      This is the only method that uses EcoGrid classes for its implementation.  
547
     *      It does so because it takes an EcoGrid Query as input, and outputs an
548
     *      EcoGrid ResultSet document.  These documents are parsed by the auto-generated
549
     *      EcoGrid classes from axis, and so we link to them here rather than re-inventing them.
550
     *      This creates a circular dependency, because the Metacat classes are needed
551
     *      to build the EcoGrid implementation, and the EcoGrid jars are needed to build this query()
552
     *      method.  This circularity could be resolved by moving the EcoGrid classes
553
     *      to Metacat directly.  As we transition away from EcoGrid SOAP methods in
554
     *      favor of these REST interfaces, this circular dependency can be eliminated.
555
     *        
556
     * @throws Exception
557
     */
558
    private void query() throws Exception {
559
        /*  This block commented out because of the EcoGrid circular dependency.
560
         *  For now, query will not be supported until the circularity can be
561
         *  resolved, probably by moving the ecogrid query syntax transformers
562
         *  directly into the Metacat codebase.  MBJ 2010-02-03
563
         
564
        try {
565
            EcogridQueryParser parser = new EcogridQueryParser(request
566
                    .getReader());
567
            parser.parseXML();
568
            QueryType queryType = parser.getEcogridQuery();
569
            EcogridJavaToMetacatJavaQueryTransformer queryTransformer = 
570
                new EcogridJavaToMetacatJavaQueryTransformer();
571
            QuerySpecification metacatQuery = queryTransformer
572
                    .transform(queryType);
573

    
574
            DBQuery metacat = new DBQuery();
575

    
576
            boolean useXMLIndex = (new Boolean(PropertyService
577
                    .getProperty("database.usexmlindex"))).booleanValue();
578
            String xmlquery = "query"; // we don't care the query in resultset,
579
            // the query can be anything
580
            PrintWriter out = null; // we don't want metacat result, so set out null
581

    
582
            // parameter: queryspecification, user, group, usingIndexOrNot
583
            StringBuffer result = metacat.createResultDocument(xmlquery,
584
                    metacatQuery, out, username, groupNames, useXMLIndex);
585

    
586
            // create result set transfer		
587
            String saxparser = PropertyService.getProperty("xml.saxparser");
588
            MetacatResultsetParser metacatResultsetParser = new MetacatResultsetParser(
589
                    new StringReader(result.toString()), saxparser, queryType
590
                            .getNamespace().get_value());
591
            ResultsetType records = metacatResultsetParser.getEcogridResult();
592

    
593
            System.out
594
                    .println(EcogridResultsetTransformer.toXMLString(records));
595
            response.setContentType("text/xml");
596
            out = response.getWriter();
597
            out.print(EcogridResultsetTransformer.toXMLString(records));
598

    
599
        } catch (Exception e) {
600
            e.printStackTrace();
601
        }*/
602
        response.setContentType("text/xml");
603
        PrintWriter out = response.getWriter();
604
        out.print("<error>Query operation not yet supported by Metacat.</error>");
605
        out.close();
606
    }
607
    
608
    /**
609
     * Earthgrid API > Put Service >Put Function : calls MetacatHandler > handleInsertOrUpdateAction 
610
     * 
611
     * @param guid ID of data object to be inserted or updated
612
     * @throws IOException
613
     */
614
    private void putObject(String guid, String action) {
615
        logMetacat.debug("Entering putObject: " + guid + "/" + action);
616
        
617
        // TODO: This function lacks proper handling of authz and authn, so it
618
        // seems that anyone can insert or update; interacts with 
619
        // loadSessionData(), which doesn't validate the session
620
        
621
        // Get an output stream for handling errors; this should really be passed in as
622
        // a parameter
623
        OutputStream out = null;
624
        try {
625
            out = response.getOutputStream();
626
        } catch (IOException e1) {
627
            logMetacat.error("Could not get the output stream for writing in putObject");
628
        }
629
        try {
630
            if (action.equals(FUNCTION_NAME_UPDATE)
631
                    || action.equals(FUNCTION_NAME_INSERT)) {
632

    
633
                // Check if the objectId exists
634
                IdentifierManager im = IdentifierManager.getInstance();
635
                if (im.identifierExists(guid)) {
636
                    throw new IdentifierNotUnique(1000, "Identifier is already in use: " + guid);
637
                }
638

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

    
641
                // Read the incoming data from its Mime Multipart encoding
642
                logMetacat.debug("Disassembling MIME multipart form");
643
                InputStream object = null;
644
                InputStream sysmeta = null;
645
                MimeMultipart mmp = new MimeMultipart(new InputStreamDataSource("message", request.getInputStream()));
646
                logMetacat.debug("MMP created.");
647
                mmp.writeTo(System.out);
648
                for (int i = 0; i < mmp.getCount(); i++) {
649
                    logMetacat.debug("Looping over MMP parts: " + i);
650
                    BodyPart part = mmp.getBodyPart(i);
651
                    String name = part.getFileName();
652
                    logMetacat.debug("Part name is: " + name);
653
                    logMetacat.debug("Part has class name: " + part.getClass().getName());
654
                    if (name.equals("object")) {
655
                        object = part.getInputStream();
656
                        logMetacat.debug("Found object part, size is: " + part.getSize());
657
                    } else if (name.equals("systemmetadata")) {
658
                        sysmeta = part.getInputStream();
659
                        logMetacat.debug("Found sysmeta part, size is: " + part.getSize());
660
                    } else {
661
                        throw new InvalidRequest(1000, "Request had malformed MIME part with name: " + name);
662
                    }
663
                }
664

    
665
                // TODO: access control -- should be in CrudService et al. I think
666
                //if (username != null && !username.equals("public")) {
667
                if (username != null) {
668

    
669
                    logMetacat.debug("Commence creation...");
670
                    AuthToken token = null;
671
                    IBindingFactory bfact =
672
                        BindingDirectory.getFactory(SystemMetadata.class);
673
                    IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
674
                    SystemMetadata m = (SystemMetadata) uctx.unmarshalDocument(sysmeta, null);
675

    
676
                    //CrudService cs = new CrudService(servletContext, request, response);
677
                    CrudService cs = CrudService.getInstance();
678
                    cs.setParamsFromRequest(request);
679
                    Identifier id = new Identifier();
680
                    id.setValue(guid);
681
                    cs.create(token, id, object, m);
682

    
683
                } else {
684
                    logMetacat.debug("Unauthorized to create.");
685
                    throw new NotAuthorized(1000, "Permission denied for user " + username);
686
                }
687
            } else {
688
                throw new InvalidRequest(1000, "Operation must be create or update.");
689
            }
690
        } catch (NotAuthorized e) {
691
            serializeException(e, out);
692
        } catch (InvalidToken e) {
693
            serializeException(e, out);
694
        } catch (ServiceFailure e) {
695
            serializeException(e, out);
696
        } catch (IdentifierNotUnique e) {
697
            serializeException(e, out);
698
        } catch (UnsupportedType e) {
699
            serializeException(e, out);
700
        } catch (InsufficientResources e) {
701
            serializeException(e, out);
702
        } catch (InvalidSystemMetadata e) {
703
            serializeException(e, out);
704
        } catch (NotImplemented e) {
705
            serializeException(e, out);
706
        } catch (InvalidRequest e) {
707
            serializeException(e, out);
708
        } catch (MessagingException e) {
709
            ServiceFailure sf = new ServiceFailure(1000, e.getMessage());
710
            serializeException(sf, out);
711
        } catch (IOException e) {
712
            ServiceFailure sf = new ServiceFailure(1000, e.getMessage());
713
            serializeException(sf, out);
714
        } catch (JiBXException e) {
715
            e.printStackTrace(System.out);
716
            InvalidSystemMetadata ism = new InvalidSystemMetadata(1080, e.getMessage());
717
            serializeException(ism, out);
718
        }
719
    }
720

    
721
    /**
722
     * Earthgrid API > Put Service > Delete Function : calls MetacatHandler > handleDeleteAction  
723
     * 
724
     * @param guid ID of data object to be deleted
725
     * @throws IOException
726
     */
727
    private void deleteObject(String guid) throws IOException 
728
    {
729
        // Look up the localId for this global identifier
730
        IdentifierManager im = IdentifierManager.getInstance();
731
        String localId = "";
732
        try {
733
            localId = im.getLocalId(guid);
734
        } catch (McdbDocNotFoundException e) {
735
            // TODO: Need to return the proper DataONE exception
736
        }
737
        
738
        params.put("docid", new String[] { localId });
739
        PrintWriter out = response.getWriter();
740
        handler.handleDeleteAction(out, params, request, response, username,
741
                groupNames);
742
        out.close();
743
    }
744

    
745
    /**
746
     * Earthgrid API > Authentication Service > Login Function : calls MetacatHandler > handleLoginAction
747
     * 
748
     * @throws IOException
749
     */
750
    private void login() throws IOException {
751
        PrintWriter out = response.getWriter();
752
        handler.handleLoginAction(out, params, request, response);
753
        out.close();
754
    }
755

    
756
    /**
757
     * Earthgrid API > Authentication Service > Logout Function : calls MetacatHandler > handleLogoutAction
758
     * 
759
     * @throws IOException
760
     */
761
    private void logout() throws IOException {
762
        PrintWriter out = response.getWriter();
763
        handler.handleLogoutAction(out, params, request, response);
764
        out.close();
765
    }
766

    
767
    /**
768
     * Prints xml response
769
     * @param message Message to be displayed
770
     * @param response Servlet response that xml message will be printed 
771
     * */
772
    private void printError(String message, HttpServletResponse response) {
773
        try {
774
            PrintWriter out = response.getWriter();
775
            response.setContentType("text/xml");
776
            out.println("<?xml version=\"1.0\"?>");
777
            out.println("<error>");
778
            out.println(message);
779
            out.println("</error>");
780
            out.close();
781
        } catch (IOException e) {
782
            e.printStackTrace();
783
        }
784
    }
785

    
786
    private void serializeException(BaseException e, OutputStream out) {
787
        // TODO: Use content negotiation to determine which return format to use
788
        response.setContentType("text/xml");
789
        response.setStatus(e.getCode());
790
        try {
791
            IOUtils.write(e.serialize(BaseException.FMT_XML), out);
792
        } catch (IOException e1) {
793
            logMetacat.error("Error writing exception to stream. " 
794
                    + e1.getMessage());
795
        }
796
    }
797

    
798
}
(2-2/3)