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.exceptions.NotFound;
54
import org.dataone.service.types.AuthToken;
55
import org.dataone.service.types.Identifier;
56
import org.dataone.service.types.SystemMetadata;
57
import org.jibx.runtime.BindingDirectory;
58
import org.jibx.runtime.IBindingFactory;
59
import org.jibx.runtime.IMarshallingContext;
60
import org.jibx.runtime.IUnmarshallingContext;
61
import org.jibx.runtime.JiBXException;
62

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

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

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

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

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

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

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

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

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

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

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

    
238
        String name = null;
239
        String[] value = null;
240
        Enumeration paramlist = request.getParameterNames();
241
        while (paramlist.hasMoreElements()) {
242
            name = (String) paramlist.nextElement();
243
            value = request.getParameterValues(name);
244
            System.out.println("adding param: " + name + " = " + value);
245
            params.put(name, value);
246
        }
247

    
248
    }
249

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

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

    
264
        if (username == null) {
265
            username = "public";
266
        }
267
    }
268

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

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

    
280
            boolean status = false;
281

    
282
            if (resource != null) {
283
                resource = request.getServletPath().substring(1);
284

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
466
        out.close();
467
    }
468

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

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

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

    
572
            DBQuery metacat = new DBQuery();
573

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

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

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

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

    
597
        } catch (Exception e) {
598
            e.printStackTrace();
599
        }*/
600
        response.setContentType("text/xml");
601
        PrintWriter out = response.getWriter();
602
        out.print("<error>Query operation not yet supported by Metacat.</error>");
603
        out.close();
604
    }
605
    
606
    /**
607
     * Earthgrid API > Put Service >Put Function : calls MetacatHandler > handleInsertOrUpdateAction 
608
     * 
609
     * @param guid ID of data object to be inserted or updated
610
     * @throws IOException
611
     */
612
    private void putObject(String guid, String action) {
613
        logMetacat.debug("Entering putObject: " + guid + "/" + action);
614
        System.out.println("entering putObject.  Action is " + action);
615
        
616
        // TODO: This function lacks proper handling of authz and authn, so it
617
        // seems that anyone can insert or update; interacts with 
618
        // loadSessionData(), which doesn't validate the session
619
        
620
        // Get an output stream for handling errors; this should really be passed in as
621
        // a parameter
622
        OutputStream out = null;
623
        try {
624
            out = response.getOutputStream();
625
        } catch (IOException e1) {
626
            logMetacat.error("Could not get the output stream for writing in putObject");
627
        }
628
        try {
629
            
630
            // Read the incoming data from its Mime Multipart encoding
631
            logMetacat.debug("Disassembling MIME multipart form");
632
            InputStream object = null;
633
            InputStream sysmeta = null;
634
            MimeMultipart mmp = new MimeMultipart(new InputStreamDataSource("message", request.getInputStream()));
635
            logMetacat.debug("MMP created.");
636
            mmp.writeTo(System.out);
637
            for (int i = 0; i < mmp.getCount(); i++) {
638
                logMetacat.debug("Looping over MMP parts: " + i);
639
                BodyPart part = mmp.getBodyPart(i);
640
                String name = part.getFileName();
641
                logMetacat.debug("Part name is: " + name);
642
                System.out.println("part name: " + name);
643
                logMetacat.debug("Part has class name: " + part.getClass().getName());
644
                if (name.equals("object")) {
645
                    object = part.getInputStream();
646
                    logMetacat.debug("Found object part, size is: " + part.getSize());
647
                } else if (name.equals("systemmetadata")) {
648
                    sysmeta = part.getInputStream();
649
                    logMetacat.debug("Found sysmeta part, size is: " + part.getSize());
650
                } else {
651
                    throw new InvalidRequest(1000, "Request had malformed MIME part with name: " + name);
652
                }
653
            }
654
            
655
            if ( action.equals(FUNCTION_NAME_INSERT)) { //handle inserts
656

    
657
                // Check if the objectId exists
658
                IdentifierManager im = IdentifierManager.getInstance();
659
                if (im.identifierExists(guid)) {
660
                    throw new IdentifierNotUnique(1000, "Identifier is already in use: " + guid);
661
                }
662

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

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

    
674
                    CrudService cs = CrudService.getInstance();
675
                    cs.setParamsFromRequest(request);
676
                    Identifier id = new Identifier();
677
                    id.setValue(guid);
678
                    cs.create(token, id, object, m);
679

    
680
                } else {
681
                    logMetacat.debug("Unauthorized to create.");
682
                    throw new NotAuthorized(1000, "Permission denied for user " + username);
683
                }
684
            } else if (action.equals(FUNCTION_NAME_UPDATE)) { //handle updates
685
                IdentifierManager im = IdentifierManager.getInstance();
686
                CrudService cs = CrudService.getInstance();
687
                Identifier obsoletedGuid = new Identifier();
688
                Identifier id = new Identifier();
689
                id.setValue(guid);
690
                AuthToken token = null;
691
                
692
                //do some checks
693
                if(params.get("obsoletedGuid") == null)
694
                {
695
                    throw new InvalidRequest(1202, "obsoletedGuid must be contained in the request parameters.");
696
                }
697
                //get the obsoletedGuid
698
                String[] obsGuidS = params.get("obsoletedGuid");
699
                obsoletedGuid.setValue(obsGuidS[0]);
700
                
701
                if (!im.identifierExists(obsoletedGuid.getValue())) 
702
                {
703
                    throw new InvalidRequest(1202, "The guid you are trying to update does not exist.");
704
                }
705
                
706
                
707
                logMetacat.debug("Commence update...");
708
                
709
                //get the systemmetadata
710
                IBindingFactory bfact =
711
                        BindingDirectory.getFactory(SystemMetadata.class);
712
                    IUnmarshallingContext uctx = bfact.createUnmarshallingContext();
713
                    SystemMetadata m = (SystemMetadata) uctx.unmarshalDocument(sysmeta, null);
714
                
715
                //do the update
716
                try
717
                {
718
                    cs.setParamsFromRequest(request);
719
                    Identifier rId = cs.update(token, id, object, obsoletedGuid, m);
720
                    System.out.println("id returned from update " + rId.getValue());
721
                }
722
                catch(NotFound e)
723
                {
724
                    throw new InvalidRequest(1202, "The guid you are trying to update does not exist.");
725
                }
726
                
727
            } else {
728
                throw new InvalidRequest(1000, "Operation must be create or update.");
729
            }
730
        } catch (NotAuthorized e) {
731
            serializeException(e, out);
732
        } catch (InvalidToken e) {
733
            serializeException(e, out);
734
        } catch (ServiceFailure e) {
735
            serializeException(e, out);
736
        } catch (IdentifierNotUnique e) {
737
            serializeException(e, out);
738
        } catch (UnsupportedType e) {
739
            serializeException(e, out);
740
        } catch (InsufficientResources e) {
741
            serializeException(e, out);
742
        } catch (InvalidSystemMetadata e) {
743
            serializeException(e, out);
744
        } catch (NotImplemented e) {
745
            serializeException(e, out);
746
        } catch (InvalidRequest e) {
747
            serializeException(e, out);
748
        } catch (MessagingException e) {
749
            ServiceFailure sf = new ServiceFailure(1000, e.getMessage());
750
            serializeException(sf, out);
751
        } catch (IOException e) {
752
            ServiceFailure sf = new ServiceFailure(1000, e.getMessage());
753
            serializeException(sf, out);
754
        } catch (JiBXException e) {
755
            e.printStackTrace(System.out);
756
            InvalidSystemMetadata ism = new InvalidSystemMetadata(1080, e.getMessage());
757
            serializeException(ism, out);
758
        }
759
    }
760

    
761
    /**
762
     * Earthgrid API > Put Service > Delete Function : calls MetacatHandler > handleDeleteAction  
763
     * 
764
     * @param guid ID of data object to be deleted
765
     * @throws IOException
766
     */
767
    private void deleteObject(String guid) throws IOException 
768
    {
769
        // Look up the localId for this global identifier
770
        IdentifierManager im = IdentifierManager.getInstance();
771
        String localId = "";
772
        try {
773
            localId = im.getLocalId(guid);
774
        } catch (McdbDocNotFoundException e) {
775
            // TODO: Need to return the proper DataONE exception
776
        }
777
        
778
        params.put("docid", new String[] { localId });
779
        PrintWriter out = response.getWriter();
780
        handler.handleDeleteAction(out, params, request, response, username,
781
                groupNames);
782
        out.close();
783
    }
784

    
785
    /**
786
     * Earthgrid API > Authentication Service > Login Function : calls MetacatHandler > handleLoginAction
787
     * 
788
     * @throws IOException
789
     */
790
    private void login() throws IOException {
791
        PrintWriter out = response.getWriter();
792
        handler.handleLoginAction(out, params, request, response);
793
        out.close();
794
    }
795

    
796
    /**
797
     * Earthgrid API > Authentication Service > Logout Function : calls MetacatHandler > handleLogoutAction
798
     * 
799
     * @throws IOException
800
     */
801
    private void logout() throws IOException {
802
        PrintWriter out = response.getWriter();
803
        handler.handleLogoutAction(out, params, request, response);
804
        out.close();
805
    }
806

    
807
    /**
808
     * Prints xml response
809
     * @param message Message to be displayed
810
     * @param response Servlet response that xml message will be printed 
811
     * */
812
    private void printError(String message, HttpServletResponse response) {
813
        try {
814
            PrintWriter out = response.getWriter();
815
            response.setContentType("text/xml");
816
            out.println("<?xml version=\"1.0\"?>");
817
            out.println("<error>");
818
            out.println(message);
819
            out.println("</error>");
820
            out.close();
821
        } catch (IOException e) {
822
            e.printStackTrace();
823
        }
824
    }
825

    
826
    private void serializeException(BaseException e, OutputStream out) {
827
        // TODO: Use content negotiation to determine which return format to use
828
        response.setContentType("text/xml");
829
        response.setStatus(e.getCode());
830
        try {
831
            IOUtils.write(e.serialize(BaseException.FMT_XML), out);
832
        } catch (IOException e1) {
833
            logMetacat.error("Error writing exception to stream. " 
834
                    + e1.getMessage());
835
        }
836
    }
837

    
838
}
(2-2/3)