Project

General

Profile

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