Project

General

Profile

1 6264 leinfelder
/**
2
 *  '$RCSfile$'
3
 *  Copyright: 2011 Regents of the University of California and the
4
 *              National Center for Ecological Analysis and Synthesis
5
 *
6
 *   '$Author$'
7
 *     '$Date$'
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.File;
26
import java.io.FileInputStream;
27
import java.io.IOException;
28
import java.io.InputStream;
29
import java.io.OutputStream;
30
import java.text.DateFormat;
31
import java.text.ParseException;
32
import java.text.SimpleDateFormat;
33
import java.util.Date;
34
import java.util.Enumeration;
35
import java.util.Map;
36 6297 cjones
import java.util.TimeZone;
37 6679 leinfelder
import java.util.concurrent.ExecutorService;
38
import java.util.concurrent.Executors;
39 6264 leinfelder
40
import javax.servlet.ServletContext;
41
import javax.servlet.http.HttpServletRequest;
42
import javax.servlet.http.HttpServletResponse;
43 6472 leinfelder
import javax.xml.parsers.ParserConfigurationException;
44 6264 leinfelder
45 6273 leinfelder
import org.apache.commons.fileupload.FileUploadException;
46 6264 leinfelder
import org.apache.commons.io.IOUtils;
47
import org.apache.log4j.Logger;
48
import org.dataone.client.ObjectFormatCache;
49 6472 leinfelder
import org.dataone.mimemultipart.MultipartRequest;
50
import org.dataone.mimemultipart.MultipartRequestResolver;
51 6264 leinfelder
import org.dataone.service.exceptions.BaseException;
52
import org.dataone.service.exceptions.IdentifierNotUnique;
53
import org.dataone.service.exceptions.InsufficientResources;
54
import org.dataone.service.exceptions.InvalidRequest;
55
import org.dataone.service.exceptions.InvalidSystemMetadata;
56
import org.dataone.service.exceptions.InvalidToken;
57
import org.dataone.service.exceptions.NotAuthorized;
58
import org.dataone.service.exceptions.NotFound;
59
import org.dataone.service.exceptions.NotImplemented;
60
import org.dataone.service.exceptions.ServiceFailure;
61
import org.dataone.service.exceptions.SynchronizationFailed;
62
import org.dataone.service.exceptions.UnsupportedType;
63 6366 leinfelder
import org.dataone.service.types.v1.Checksum;
64
import org.dataone.service.types.v1.DescribeResponse;
65
import org.dataone.service.types.v1.Event;
66
import org.dataone.service.types.v1.Identifier;
67
import org.dataone.service.types.v1.Log;
68
import org.dataone.service.types.v1.MonitorList;
69
import org.dataone.service.types.v1.Node;
70
import org.dataone.service.types.v1.NodeReference;
71
import org.dataone.service.types.v1.ObjectFormat;
72
import org.dataone.service.types.v1.ObjectFormatIdentifier;
73
import org.dataone.service.types.v1.ObjectList;
74
import org.dataone.service.types.v1.Permission;
75
import org.dataone.service.types.v1.Subject;
76
import org.dataone.service.types.v1.SystemMetadata;
77 7019 leinfelder
import org.dataone.service.util.Constants;
78 6469 leinfelder
import org.dataone.service.util.DateTimeMarshaller;
79 6472 leinfelder
import org.dataone.service.util.ExceptionHandler;
80 6367 leinfelder
import org.dataone.service.util.TypeMarshaller;
81 6264 leinfelder
import org.jibx.runtime.JiBXException;
82 6472 leinfelder
import org.xml.sax.SAXException;
83 6264 leinfelder
84
import edu.ucsb.nceas.metacat.dataone.MNodeService;
85 6994 leinfelder
import edu.ucsb.nceas.metacat.properties.PropertyService;
86
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
87 6264 leinfelder
88
/**
89
 * MN REST service implementation handler
90
 *
91
 * ******************
92
 * MNCore -- DONE
93
 * 		ping() - GET /d1/mn/monitor/ping
94
 * 		log() - GET /d1/mn/log
95
 * 		**getObjectStatistics() - GET /d1/mn/monitor/object
96
 * 		getOperationsStatistics - GET /d1/mn/monitor/event
97
 * 		**getStatus - GET /d1/mn/monitor/status
98
 * 		getCapabilities() - GET /d1/mn/ and /d1/mn/node
99
 *
100
 * 	MNRead -- DONE
101
 * 		get() - GET /d1/mn/object/PID
102
 * 		getSystemMetadata() - GET /d1/mn/meta/PID
103
 * 		describe() - HEAD /d1/mn/object/PID
104
 * 		getChecksum() - GET /d1/mn/checksum/PID
105
 * 		listObjects() - GET /d1/mn/object
106
 * 		synchronizationFailed() - POST /d1/mn/error
107
 *
108
 * 	MNAuthorization -- DONE
109
 * 		isAuthorized() - GET /d1/mn/isAuthorized/PID
110
 * 		setAccessPolicy() - PUT /d1/mn/accessRules/PID
111
 *
112 6297 cjones
 * 	MNStorage - DONE
113 6264 leinfelder
 * 		create() - POST /d1/mn/object/PID
114
 * 		update() - PUT /d1/mn/object/PID
115
 * 		delete() - DELETE /d1/mn/object/PID
116 6619 cjones
 *    systemMetadataChanged() - POST /dirtySystemMetadata/PID
117 6264 leinfelder
 *
118
 * 	MNReplication
119
 * 		replicate() - POST /d1/mn/replicate
120 6604 cjones
 *    getReplica() - GET /d1/mn/replica
121 6264 leinfelder
 *
122
 * ******************
123
 * @author leinfelder
124
 *
125
 */
126 6267 leinfelder
public class MNResourceHandler extends D1ResourceHandler{
127 6264 leinfelder
128
    // MN-specific API Resources
129
    protected static final String RESOURCE_MONITOR = "monitor";
130
    protected static final String RESOURCE_REPLICATE = "replicate";
131 6604 cjones
    protected static final String RESOURCE_REPLICAS = "replica";
132 6264 leinfelder
    protected static final String RESOURCE_NODE = "node";
133
    protected static final String RESOURCE_ERROR = "error";
134 6619 cjones
    protected static final String RESOURCE_META_CHANGED = "dirtySystemMetadata";
135 6264 leinfelder
136
    /**
137
     * Initializes new instance by setting servlet context,request and response
138
     * */
139
    public MNResourceHandler(ServletContext servletContext,
140
            HttpServletRequest request, HttpServletResponse response) {
141
    	super(servletContext, request, response);
142
        logMetacat = Logger.getLogger(MNResourceHandler.class);
143
    }
144 6994 leinfelder
145
    @Override
146
    protected boolean isD1Enabled() {
147
148
    	boolean enabled = false;
149
    	try {
150
			enabled = Boolean.parseBoolean(PropertyService.getProperty("dataone.mn.services.enabled"));
151
		} catch (PropertyNotFoundException e) {
152
			logMetacat.error("Could not check if DataONE is enabled: " + e.getMessage());
153
		}
154
155
    	return enabled;
156
    }
157 6264 leinfelder
158
    /**
159 6271 leinfelder
     * This function is called from REST API servlet and handles each request to the servlet
160 6264 leinfelder
     *
161
     * @param httpVerb (GET, POST, PUT or DELETE)
162
     */
163 6271 leinfelder
    @Override
164 6264 leinfelder
    public void handle(byte httpVerb) {
165 6271 leinfelder
    	// prepare the handler
166
    	super.handle(httpVerb);
167
168 6264 leinfelder
        try {
169 6994 leinfelder
170
        	// only service requests if we have D1 configured
171
        	if (!isD1Enabled()) {
172
        		ServiceFailure se = new ServiceFailure("0000", "DataONE services are not enabled on this node");
173
                serializeException(se, response.getOutputStream());
174
                return;
175
        	}
176
177 6284 leinfelder
        	// get the resource
178
            String resource = request.getPathInfo();
179
            resource = resource.substring(resource.indexOf("/") + 1);
180 6264 leinfelder
181 6284 leinfelder
            // default to node info
182
            if (resource.equals("")) {
183 6264 leinfelder
                resource = RESOURCE_NODE;
184
            }
185 6284 leinfelder
186
            // get the rest of the path info
187
            String extra = null;
188 6264 leinfelder
189 6272 leinfelder
            logMetacat.debug("handling verb " + httpVerb + " request with resource '" + resource + "'");
190
            logMetacat.debug("resource: '" + resource + "'");
191 6264 leinfelder
            boolean status = false;
192
193
            if (resource != null) {
194
195 6284 leinfelder
                if (resource.startsWith(RESOURCE_NODE)) {
196 6264 leinfelder
                    // node response
197
                    node();
198
                    status = true;
199 6284 leinfelder
                } else if (resource.startsWith(RESOURCE_IS_AUTHORIZED)) {
200 6264 leinfelder
                    if (httpVerb == GET) {
201 6514 leinfelder
                    	// after the command
202
                        extra = parseTrailing(resource, RESOURCE_IS_AUTHORIZED);
203 6264 leinfelder
	                	// check the access rules
204 6284 leinfelder
	                    isAuthorized(extra);
205 6264 leinfelder
	                    status = true;
206 6272 leinfelder
	                    logMetacat.debug("done getting access");
207 6264 leinfelder
                    }
208 6284 leinfelder
                } else if (resource.startsWith(RESOURCE_META)) {
209 6272 leinfelder
                    logMetacat.debug("Using resource 'meta'");
210 6264 leinfelder
                    // get
211
                    if (httpVerb == GET) {
212 6514 leinfelder
                    	// after the command
213
                        extra = parseTrailing(resource, RESOURCE_META);
214 6284 leinfelder
                        getSystemMetadataObject(extra);
215 6264 leinfelder
                        status = true;
216
                    }
217
218 6284 leinfelder
                } else if (resource.startsWith(RESOURCE_OBJECTS)) {
219 6272 leinfelder
                    logMetacat.debug("Using resource 'object'");
220 6514 leinfelder
                    // after the command
221
                    extra = parseTrailing(resource, RESOURCE_OBJECTS);
222 6284 leinfelder
                    logMetacat.debug("objectId: " + extra);
223 6264 leinfelder
                    logMetacat.debug("verb:" + httpVerb);
224
225
                    if (httpVerb == GET) {
226 6284 leinfelder
                        getObject(extra);
227 6264 leinfelder
                        status = true;
228
                    } else if (httpVerb == POST) {
229 6972 leinfelder
                    	// part of the params, not the URL
230
                        putObject(null, FUNCTION_NAME_INSERT);
231 6264 leinfelder
                        status = true;
232
                    } else if (httpVerb == PUT) {
233 6284 leinfelder
                        putObject(extra, FUNCTION_NAME_UPDATE);
234 6264 leinfelder
                        status = true;
235
                    } else if (httpVerb == DELETE) {
236 6284 leinfelder
                        deleteObject(extra);
237 6264 leinfelder
                        status = true;
238
                    } else if (httpVerb == HEAD) {
239 6284 leinfelder
                        describeObject(extra);
240 6264 leinfelder
                        status = true;
241
                    }
242
243 6284 leinfelder
                } else if (resource.startsWith(RESOURCE_LOG)) {
244 6272 leinfelder
                    logMetacat.debug("Using resource 'log'");
245 6264 leinfelder
                    // handle log events
246
                    if (httpVerb == GET) {
247
                        getLog();
248
                        status = true;
249
                    }
250 7019 leinfelder
                } else if (resource.startsWith(Constants.RESOURCE_CHECKSUM)) {
251 6272 leinfelder
                    logMetacat.debug("Using resource 'checksum'");
252 6264 leinfelder
                    // handle checksum requests
253
                    if (httpVerb == GET) {
254 6514 leinfelder
                    	// after the command
255 7019 leinfelder
                        extra = parseTrailing(resource, Constants.RESOURCE_CHECKSUM);
256 6284 leinfelder
                        checksum(extra);
257 6264 leinfelder
                        status = true;
258
                    }
259
                } else if (resource.startsWith(RESOURCE_MONITOR)) {
260
                    // there are various parts to monitoring
261
                    if (httpVerb == GET) {
262 6514 leinfelder
                    	// after the command
263
                        extra = parseTrailing(resource, RESOURCE_MONITOR);
264 6803 leinfelder
265
                        // ping
266
                        if (extra.toLowerCase().equals("ping")) {
267
                            logMetacat.debug("processing ping request");
268
                            Date result = MNodeService.getInstance(request).ping();
269
                            // TODO: send to output
270
                            status = true;
271
272
                        } else {
273
	                    	// health monitoring calls
274
	                        status = monitor(extra);
275
                        }
276
277 6264 leinfelder
                    }
278 6284 leinfelder
                } else if (resource.startsWith(RESOURCE_REPLICATE)) {
279 6264 leinfelder
                	if (httpVerb == POST) {
280 6272 leinfelder
	                    logMetacat.debug("processing replicate request");
281 6264 leinfelder
	                    replicate();
282
	                    status = true;
283
                	}
284 6284 leinfelder
                } else if (resource.startsWith(RESOURCE_ERROR)) {
285 6264 leinfelder
	                // sync error
286
	                if (httpVerb == POST) {
287
	                    syncError();
288
	                    status = true;
289
	                }
290 6604 cjones
                } else if (resource.startsWith(RESOURCE_META_CHANGED)) {
291
                    // system metadata changed
292
                    if (httpVerb == POST) {
293 6650 leinfelder
                        systemMetadataChanged();
294 6604 cjones
                        status = true;
295
                    }
296
                } else if (resource.startsWith(RESOURCE_REPLICAS)) {
297
                    // get replica
298
                    if (httpVerb == GET) {
299
                        extra = parseTrailing(resource, RESOURCE_REPLICAS);
300
                        getReplica(extra);
301
                        status = true;
302
                    }
303 6264 leinfelder
                }
304
305
                if (!status) {
306 6273 leinfelder
                	throw new ServiceFailure("0000", "Unknown error, status = " + status);
307 6264 leinfelder
                }
308
            } else {
309 6273 leinfelder
            	throw new InvalidRequest("0000", "No resource matched for " + resource);
310 6264 leinfelder
            }
311
        } catch (BaseException be) {
312
        	// report Exceptions as clearly as possible
313
        	OutputStream out = null;
314
			try {
315
				out = response.getOutputStream();
316
			} catch (IOException e) {
317
				logMetacat.error("Could not get output stream from response", e);
318
			}
319
            serializeException(be, out);
320
        } catch (Exception e) {
321 6273 leinfelder
            // report Exceptions as clearly and generically as possible
322
            logMetacat.error(e.getClass() + ": " + e.getMessage(), e);
323
        	OutputStream out = null;
324
			try {
325
				out = response.getOutputStream();
326
			} catch (IOException ioe) {
327
				logMetacat.error("Could not get output stream from response", ioe);
328
			}
329
			ServiceFailure se = new ServiceFailure("0000", e.getMessage());
330
            serializeException(se, out);
331 6264 leinfelder
        }
332
    }
333
334 6604 cjones
335 6273 leinfelder
    /**
336 6604 cjones
     * Handles notification of system metadata changes for the given identifier
337
     *
338
     * @param id  the identifier for the object
339
     * @throws InvalidToken
340
     * @throws InvalidRequest
341
     * @throws NotAuthorized
342
     * @throws ServiceFailure
343
     * @throws NotImplemented
344
     */
345 6650 leinfelder
    private void systemMetadataChanged()
346 6604 cjones
        throws NotImplemented, ServiceFailure, NotAuthorized, InvalidRequest,
347
        InvalidToken {
348
349
        long serialVersion = 0L;
350
        String serialVersionStr = null;
351
        Date dateSysMetaLastModified = null;
352
        String dateSysMetaLastModifiedStr = null;
353 6650 leinfelder
        Identifier pid = null;
354 6604 cjones
355 6660 leinfelder
        // mkae sure we have the multipart params
356
        try {
357
			initMultipartParams();
358
		} catch (Exception e1) {
359
			throw new ServiceFailure("1333", "Could not collect the multipart params for the request");
360
		}
361
362 6650 leinfelder
        // get the pid
363
        try {
364 6660 leinfelder
        	String id = multipartparams.get("pid").get(0);
365 6650 leinfelder
        	pid = new Identifier();
366
            pid.setValue(id);
367
        } catch (NullPointerException e) {
368
            String msg = "The 'pid' must be provided as a parameter and was not.";
369
            logMetacat.error(msg);
370
            throw new InvalidRequest("1334", msg);
371
        }
372
373 6604 cjones
        // get the serialVersion
374
        try {
375 6660 leinfelder
            serialVersionStr = multipartparams.get("serialVersion").get(0);
376 6604 cjones
            serialVersion = new Long(serialVersionStr).longValue();
377
378
        } catch (NullPointerException e) {
379
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
380
            logMetacat.error(msg);
381
            throw new InvalidRequest("1334", msg);
382
383
        }
384
385
        // get the dateSysMetaLastModified
386
        try {
387 6660 leinfelder
            dateSysMetaLastModifiedStr = multipartparams.get("dateSysMetaLastModified").get(0);
388 6604 cjones
            dateSysMetaLastModified = DateTimeMarshaller.deserializeDateToUTC(dateSysMetaLastModifiedStr);
389
390
        } catch (NullPointerException e) {
391
            String msg =
392
                "The 'dateSysMetaLastModified' must be provided as a " +
393
                "parameter and was not, or was an invalid representation of the timestamp.";
394
            logMetacat.error(msg);
395
            throw new InvalidRequest("1334", msg);
396
397
        }
398
399
        // call the service
400
        MNodeService.getInstance(request).systemMetadataChanged(session, pid, serialVersion, dateSysMetaLastModified);
401
        response.setStatus(200);
402
    }
403
404
    /**
405 6273 leinfelder
     * Checks the access policy
406
     * @param id
407
     * @return
408
     * @throws ServiceFailure
409
     * @throws InvalidToken
410
     * @throws NotFound
411
     * @throws NotAuthorized
412
     * @throws NotImplemented
413
     * @throws InvalidRequest
414
     */
415 6264 leinfelder
    private boolean isAuthorized(String id) throws ServiceFailure, InvalidToken, NotFound, NotAuthorized, NotImplemented, InvalidRequest {
416
		Identifier pid = new Identifier();
417
		pid.setValue(id);
418
		Permission permission = null;
419
		try {
420 6509 leinfelder
			String perm = params.get("action")[0];
421 6373 leinfelder
			permission = Permission.convert(perm);
422 6264 leinfelder
		} catch (Exception e) {
423
			logMetacat.warn("No permission specified");
424
		}
425 6542 leinfelder
		boolean result = MNodeService.getInstance(request).isAuthorized(session, pid, permission);
426 6264 leinfelder
		response.setStatus(200);
427
		response.setContentType("text/xml");
428
		return result;
429
    }
430
431 6273 leinfelder
    /**
432
     * Processes failed synchronization message
433
     * @throws NotImplemented
434
     * @throws ServiceFailure
435
     * @throws NotAuthorized
436
     * @throws InvalidRequest
437
     * @throws JiBXException
438 6367 leinfelder
     * @throws IllegalAccessException
439
     * @throws InstantiationException
440
     * @throws IOException
441 6273 leinfelder
     */
442 6367 leinfelder
    private void syncError() throws NotImplemented, ServiceFailure, NotAuthorized, InvalidRequest, JiBXException, IOException, InstantiationException, IllegalAccessException {
443 6264 leinfelder
    	SynchronizationFailed syncFailed = null;
444 6472 leinfelder
		try {
445
			syncFailed = collectSynchronizationFailed();
446
		} catch (ParserConfigurationException e) {
447
			throw new ServiceFailure("2161", e.getMessage());
448
		} catch (SAXException e) {
449
			throw new ServiceFailure("2161", e.getMessage());
450
		}
451
452 6542 leinfelder
		MNodeService.getInstance(request).synchronizationFailed(session, syncFailed);
453 6264 leinfelder
    }
454
455 6472 leinfelder
456 6273 leinfelder
    /**
457
     * Handles the monitoring resources
458
     * @return
459
     * @throws NotFound
460
     * @throws ParseException
461
     * @throws NotImplemented
462
     * @throws ServiceFailure
463
     * @throws NotAuthorized
464
     * @throws InvalidRequest
465
     * @throws InsufficientResources
466
     * @throws UnsupportedType
467
     * @throws IOException
468
     * @throws JiBXException
469
     */
470 6297 cjones
    private boolean monitor(String pathInfo)
471
      throws NotFound, ParseException, NotImplemented, ServiceFailure,
472
      NotAuthorized, InvalidRequest, InsufficientResources, UnsupportedType,
473
      IOException, JiBXException {
474 6272 leinfelder
    	logMetacat.debug("processing monitor request");
475 6264 leinfelder
476 6272 leinfelder
        logMetacat.debug("verb is GET");
477
        logMetacat.debug("pathInfo is " + pathInfo);
478 6264 leinfelder
479 6803 leinfelder
        if (pathInfo.toLowerCase().equals("status")) {
480 6272 leinfelder
            logMetacat.debug("processing status request");
481 6264 leinfelder
            // TODO: implement in MNCore
482
            //MNodeService.getInstance().getStatus();
483
            return false;
484
485
        } else if (pathInfo.toLowerCase().equals("object")) {
486 6272 leinfelder
            logMetacat.debug("processing object request");
487 6264 leinfelder
            Identifier pid = null;
488
            ObjectFormat format = null;
489
            if (params.containsKey("format")) {
490
                String f = params.get("format")[0];
491
                format = ObjectFormatCache.getInstance().getFormat(f);
492
            }
493
            if (params.containsKey("pid")) {
494
                String id = params.get("pid")[0];
495
                pid = new Identifier();
496
                pid.setValue(id);
497
            }
498
499
            // TODO: implement in MNCore
500
            //ObjectStatistics objectStats = MNodeService.getInstance().getObjectStatistics(format, pid);
501 6274 leinfelder
            return false;
502 6264 leinfelder
503
        } else if (pathInfo.toLowerCase().equals("event")) {
504 6272 leinfelder
            logMetacat.debug("processing event request");
505 6297 cjones
            ObjectFormatIdentifier fmtid = null;
506
            String fromDateStr = null;
507
            Date fromDate = null;
508
            String toDateStr = null;
509
            Date toDate = null;
510 6264 leinfelder
            String requestor = null;
511
            Subject subject = null;
512
            String eventName = null;
513
            Event event = null;
514
515 6297 cjones
            if (params.containsKey("formatId")) {
516
                String f = params.get("formatId")[0];
517 6561 leinfelder
                fmtid = ObjectFormatCache.getInstance().getFormat(f).getFormatId();
518 6264 leinfelder
            }
519 6297 cjones
520
            if (params.containsKey("fromDate")) {
521
                fromDateStr = params.get("fromDate")[0];
522
                fromDate = getDateAsUTC(fromDateStr);
523 6264 leinfelder
            }
524 6297 cjones
525
            if (params.containsKey("toDate")) {
526
              toDateStr = params.get("toDate")[0];
527
              toDate = getDateAsUTC(toDateStr);
528
            }
529
530 6264 leinfelder
            if (params.containsKey("requestor")) {
531
            	requestor = params.get("requestor")[0];
532
            	subject = new Subject();
533
            	subject.setValue(requestor);
534
            }
535 6297 cjones
536 6264 leinfelder
            if (params.containsKey("event")) {
537
            	eventName = params.get("event")[0];
538 6373 leinfelder
                event = Event.convert(eventName);
539 6264 leinfelder
            }
540
541 6542 leinfelder
            MonitorList monitorList = MNodeService.getInstance(request).getOperationStatistics(session, fromDate, toDate, subject, event, fmtid);
542 6264 leinfelder
543
            OutputStream out = response.getOutputStream();
544
            response.setStatus(200);
545
            response.setContentType("text/xml");
546
547 6367 leinfelder
            TypeMarshaller.marshalTypeToOutputStream(monitorList, out);
548 6264 leinfelder
549 6274 leinfelder
            return true;
550
551 6264 leinfelder
        }
552
553 6274 leinfelder
        return false;
554 6264 leinfelder
    }
555
556 6297 cjones
    /*
557
     * Parse an ISO8601 date string, returning a Date in UTC time if the string
558
     * ends in 'Z'.
559
     *
560
     * @param fromDateStr -  the date string to be parsed
561
     * @return date -  the date object represented by the string
562
     */
563
    private Date getDateAsUTC(String fromDateStr)
564
      throws ParseException {
565
566
    	Date date = null;
567
568
    	try {
569
    		// try the expected date format
570
        // a date format for date string arguments
571
        DateFormat dateFormat =
572
        	new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
573
574
	      date = dateFormat.parse(fromDateStr);
575
576
    	} catch (ParseException e) {
577
    		// try the date with the UTC indicator
578
        DateFormat utcDateFormat =
579
        	new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'");
580
        utcDateFormat.setTimeZone(TimeZone.getTimeZone("GMT-0"));
581
        date = utcDateFormat.parse(fromDateStr);
582
583
      }
584
585
    	return date;
586
    }
587
588
		/**
589 6273 leinfelder
     * Calculate the checksum
590
     * @throws NotImplemented
591
     * @throws JiBXException
592
     * @throws IOException
593
     * @throws InvalidToken
594
     * @throws ServiceFailure
595
     * @throws NotAuthorized
596
     * @throws NotFound
597
     * @throws InvalidRequest
598
     */
599 6285 cjones
    private void checksum(String pid) throws NotImplemented, JiBXException, IOException, InvalidToken, ServiceFailure, NotAuthorized, NotFound, InvalidRequest {
600 6264 leinfelder
    	String checksumAlgorithm = "MD5";
601 6284 leinfelder
602 6285 cjones
        Identifier pidid = new Identifier();
603
        pidid.setValue(pid);
604 6264 leinfelder
        try {
605
            checksumAlgorithm = params.get("checksumAlgorithm")[0];
606
        } catch(Exception e) {
607
            //do nothing.  default to MD5
608
        	logMetacat.warn("No algorithm specified, using default: " + checksumAlgorithm);
609
        }
610 6285 cjones
        logMetacat.debug("getting checksum for object " + pid + " with algorithm " + checksumAlgorithm);
611 6273 leinfelder
612 6542 leinfelder
        Checksum c = MNodeService.getInstance(request).getChecksum(session, pidid, checksumAlgorithm);
613 6273 leinfelder
        logMetacat.debug("got checksum " + c.getValue());
614
        response.setStatus(200);
615
        logMetacat.debug("serializing response");
616 6367 leinfelder
        TypeMarshaller.marshalTypeToOutputStream(c, response.getOutputStream());
617 6273 leinfelder
        logMetacat.debug("done serializing response.");
618
619 6264 leinfelder
    }
620
621
	/**
622
     * handle the replicate action for MN
623 6273 leinfelder
	 * @throws JiBXException
624
	 * @throws FileUploadException
625
	 * @throws IOException
626
	 * @throws InvalidRequest
627
	 * @throws ServiceFailure
628
	 * @throws UnsupportedType
629
	 * @throws InsufficientResources
630
	 * @throws NotAuthorized
631
	 * @throws NotImplemented
632 6367 leinfelder
	 * @throws IllegalAccessException
633
	 * @throws InstantiationException
634 6264 leinfelder
     */
635 6678 cjones
    private void replicate()
636
        throws ServiceFailure, InvalidRequest, IOException, FileUploadException,
637
        JiBXException, NotImplemented, NotAuthorized, InsufficientResources,
638
        UnsupportedType, InstantiationException, IllegalAccessException {
639 6264 leinfelder
640 6272 leinfelder
        logMetacat.debug("in POST replicate()");
641 6264 leinfelder
642 7064 leinfelder
        // somewhat unorthodox, but the call is asynchronous and we'd like to return this info sooner
643
        if (session == null) {
644
        	String msg = "No session was provided.";
645
            NotAuthorized failure = new NotAuthorized("2152", msg);
646
        	throw failure;
647
        }
648
649 6273 leinfelder
        //parse the systemMetadata
650 6679 leinfelder
        final SystemMetadata sysmeta = collectSystemMetadata();
651 6264 leinfelder
652 6273 leinfelder
        String sn = multipartparams.get("sourceNode").get(0);
653 6272 leinfelder
        logMetacat.debug("sourceNode: " + sn);
654 6679 leinfelder
        final NodeReference sourceNode = new NodeReference();
655 6548 cjones
        sourceNode.setValue(sn);
656 6679 leinfelder
657
        // run it in a thread to avoid connection timeout
658
        Runnable runner = new Runnable() {
659
			@Override
660
			public void run() {
661
				try {
662
			        MNodeService.getInstance(request).replicate(session, sysmeta, sourceNode);
663
				} catch (Exception e) {
664 7091 leinfelder
					logMetacat.error("Error running replication: " + e.getMessage(), e);
665 6679 leinfelder
					throw new RuntimeException(e.getMessage(), e);
666
				}
667
			}
668
    	};
669
    	ExecutorService executor = Executors.newSingleThreadExecutor();
670
    	executor.execute(runner);
671
    	executor.shutdown();
672
673
    	// thread was started, so we return success
674 6678 cjones
        response.setStatus(200);
675 6679 leinfelder
676 6264 leinfelder
    }
677 6604 cjones
678 6264 leinfelder
    /**
679 6604 cjones
     * Handle the getReplica action for the MN
680
     * @param id  the identifier for the object
681
     * @throws NotFound
682
     * @throws ServiceFailure
683
     * @throws NotImplemented
684
     * @throws NotAuthorized
685
     * @throws InvalidToken
686
     * @throws InvalidRequest
687
     */
688
    private void getReplica(String id)
689
        throws InvalidRequest, InvalidToken, NotAuthorized, NotImplemented,
690
        ServiceFailure, NotFound {
691
692
        Identifier pid = new Identifier();
693
        pid.setValue(id);
694
        OutputStream out = null;
695
        InputStream dataBytes = null;
696
697
        try {
698
            // call the service
699
            dataBytes = MNodeService.getInstance(request).getReplica(session, pid);
700
701
            response.setContentType("application/octet-stream");
702
            response.setStatus(200);
703
            out = response.getOutputStream();
704
            // write the object to the output stream
705
            IOUtils.copyLarge(dataBytes, out);
706
707
        } catch (IOException e) {
708
            String msg = "There was an error writing the output: " + e.getMessage();
709
            logMetacat.error(msg);
710
            throw new ServiceFailure("2181", msg);
711
712
        }
713
714
    }
715
716
    /**
717 6264 leinfelder
     * Get the Node information
718
     *
719
     * @throws JiBXException
720
     * @throws IOException
721
     * @throws InvalidRequest
722
     * @throws ServiceFailure
723
     * @throws NotAuthorized
724
     * @throws NotImplemented
725
     */
726
    private void node()
727
        throws JiBXException, IOException, NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest {
728
729 6542 leinfelder
        Node n = MNodeService.getInstance(request).getCapabilities();
730 6264 leinfelder
731
        response.setContentType("text/xml");
732
        response.setStatus(200);
733 6501 leinfelder
        TypeMarshaller.marshalTypeToOutputStream(n, response.getOutputStream());
734 6264 leinfelder
735
    }
736
737
    /**
738
     * MN_crud.describe()
739
     * http://mule1.dataone.org/ArchitectureDocs/mn_api_crud.html#MN_crud.describe
740 6285 cjones
     * @param pid
741 6273 leinfelder
     * @throws InvalidRequest
742
     * @throws NotImplemented
743
     * @throws NotFound
744
     * @throws NotAuthorized
745
     * @throws ServiceFailure
746
     * @throws InvalidToken
747 6264 leinfelder
     */
748 6285 cjones
    private void describeObject(String pid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, InvalidRequest
749 6264 leinfelder
    {
750 7043 leinfelder
751 6264 leinfelder
        response.setContentType("text/xml");
752 7043 leinfelder
753 6264 leinfelder
        Identifier id = new Identifier();
754 6285 cjones
        id.setValue(pid);
755 6273 leinfelder
756 7043 leinfelder
        DescribeResponse dr = null;
757
        try {
758
        	dr = MNodeService.getInstance(request).describe(session, id);
759
        } catch (BaseException e) {
760
        	response.setStatus(e.getCode());
761
        	response.addHeader("DataONE-Exception-Name", e.getClass().getName());
762
            response.addHeader("DataONE-Exception-DetailCode", e.getDetail_code());
763
            response.addHeader("DataONE-Exception-Description", e.getDescription());
764
            response.addHeader("DataONE-Exception-PID", id.getValue());
765
            return;
766
		}
767
768
        response.setStatus(200);
769
770 6502 leinfelder
        //response.addHeader("pid", pid);
771 6507 leinfelder
        response.addHeader("DataONE-Checksum", dr.getDataONE_Checksum().getAlgorithm() + "," + dr.getDataONE_Checksum().getValue());
772 6502 leinfelder
        response.addHeader("Content-Length", dr.getContent_Length() + "");
773
        response.addHeader("Last-Modified", DateTimeMarshaller.serializeDateToUTC(dr.getLast_Modified()));
774 6691 leinfelder
        response.addHeader("DataONE-ObjectFormat", dr.getDataONE_ObjectFormatIdentifier().getValue());
775 6773 leinfelder
        response.addHeader("DataONE-SerialVersion", dr.getSerialVersion().toString());
776
777 6502 leinfelder
778 6264 leinfelder
    }
779
780
    /**
781
     * get the logs based on passed params.  Available
782
     * See http://mule1.dataone.org/ArchitectureDocs/mn_api_crud.html#MN_crud.getLogRecords
783
     * for more info
784 6273 leinfelder
     * @throws NotImplemented
785
     * @throws InvalidRequest
786
     * @throws NotAuthorized
787
     * @throws ServiceFailure
788
     * @throws InvalidToken
789
     * @throws IOException
790
     * @throws JiBXException
791 6264 leinfelder
     */
792 6273 leinfelder
    private void getLog() throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest, NotImplemented, IOException, JiBXException
793 6264 leinfelder
    {
794 6273 leinfelder
795
        Date fromDate = null;
796
        Date toDate = null;
797
        Event event = null;
798
        Integer start = null;
799
        Integer count = null;
800 7099 leinfelder
        String pidFilter = null;
801 6273 leinfelder
802 6264 leinfelder
        try {
803 6273 leinfelder
        	String fromDateS = params.get("fromDate")[0];
804
            logMetacat.debug("param fromDateS: " + fromDateS);
805 6469 leinfelder
            fromDate = DateTimeMarshaller.deserializeDateToUTC(fromDateS);
806 6273 leinfelder
        } catch (Exception e) {
807
        	logMetacat.warn("Could not parse fromDate: " + e.getMessage());
808 6264 leinfelder
        }
809 6273 leinfelder
        try {
810
        	String toDateS = params.get("toDate")[0];
811
            logMetacat.debug("param toDateS: " + toDateS);
812 6469 leinfelder
            toDate = DateTimeMarshaller.deserializeDateToUTC(toDateS);
813 6273 leinfelder
        } catch (Exception e) {
814
        	logMetacat.warn("Could not parse toDate: " + e.getMessage());
815
		}
816
        try {
817
        	String eventS = params.get("event")[0];
818
            event = Event.convert(eventS);
819
        } catch (Exception e) {
820
        	logMetacat.warn("Could not parse event: " + e.getMessage());
821
		}
822
        logMetacat.debug("fromDate: " + fromDate + " toDate: " + toDate);
823
824
        try {
825
        	start =  Integer.parseInt(params.get("start")[0]);
826
        } catch (Exception e) {
827
			logMetacat.warn("Could not parse start: " + e.getMessage());
828
		}
829
        try {
830
        	count =  Integer.parseInt(params.get("count")[0]);
831
        } catch (Exception e) {
832
			logMetacat.warn("Could not parse count: " + e.getMessage());
833
		}
834
835 7099 leinfelder
        try {
836
            pidFilter = params.get("pidFilter")[0];
837
        } catch (Exception e) {
838
            logMetacat.warn("Could not parse pidFilter: " + e.getMessage());
839
        }
840
841 6273 leinfelder
        logMetacat.debug("calling getLogRecords");
842 7101 leinfelder
        Log log = MNodeService.getInstance(request).getLogRecords(session, fromDate, toDate, event, pidFilter, start, count);
843 6273 leinfelder
844
        OutputStream out = response.getOutputStream();
845
        response.setStatus(200);
846
        response.setContentType("text/xml");
847
848 6367 leinfelder
        TypeMarshaller.marshalTypeToOutputStream(log, out);
849 6273 leinfelder
850 6264 leinfelder
    }
851
852
    /**
853
     * Implements REST version of DataONE CRUD API --> get
854 6285 cjones
     * @param pid ID of data object to be read
855 6273 leinfelder
     * @throws NotImplemented
856
     * @throws InvalidRequest
857
     * @throws NotFound
858
     * @throws NotAuthorized
859
     * @throws ServiceFailure
860
     * @throws InvalidToken
861
     * @throws IOException
862
     * @throws JiBXException
863 6264 leinfelder
     */
864 6285 cjones
    protected void getObject(String pid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, InvalidRequest, NotImplemented, IOException, JiBXException {
865 6264 leinfelder
        OutputStream out = null;
866 6273 leinfelder
867 6285 cjones
        if (pid != null) { //get a specific document
868 6273 leinfelder
            Identifier id = new Identifier();
869 6285 cjones
            id.setValue(pid);
870 6273 leinfelder
871 6542 leinfelder
            SystemMetadata sm = MNodeService.getInstance(request).getSystemMetadata(session, id);
872 6264 leinfelder
873 6273 leinfelder
            //set the content type
874 6561 leinfelder
            if (sm.getFormatId().getValue().trim().equals(
875
            		ObjectFormatCache.getInstance().getFormat("text/csv").getFormatId().getValue()))
876 6273 leinfelder
            {
877
                response.setContentType("text/csv");
878
                response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".csv");
879
            }
880 6561 leinfelder
            else if (sm.getFormatId().getValue().trim().equals(
881
            		ObjectFormatCache.getInstance().getFormat("text/plain").getFormatId().getValue()))
882 6273 leinfelder
            {
883
                response.setContentType("text/plain");
884
                response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".txt");
885
            }
886 6561 leinfelder
            else if (sm.getFormatId().getValue().trim().equals(
887
            		ObjectFormatCache.getInstance().getFormat("application/octet-stream").getFormatId().getValue()))
888 6273 leinfelder
            {
889
                response.setContentType("application/octet-stream");
890
            }
891
            else
892
            {
893
                response.setContentType("text/xml");
894
                response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".xml");
895
            }
896
897 6542 leinfelder
            InputStream data = MNodeService.getInstance(request).get(session, id);
898 6273 leinfelder
899
            out = response.getOutputStream();
900
            IOUtils.copyLarge(data, out);
901
902
        }
903
        else
904
        { //call listObjects with specified params
905
            Date startTime = null;
906
            Date endTime = null;
907 7100 leinfelder
            ObjectFormatIdentifier formatId = null;
908 6273 leinfelder
            boolean replicaStatus = false;
909
            int start = 0;
910
            //TODO: make the max count into a const
911
            int count = 1000;
912
            Enumeration paramlist = request.getParameterNames();
913
            while (paramlist.hasMoreElements())
914
            { //parse the params and make the crud call
915
                String name = (String) paramlist.nextElement();
916
                String[] value = (String[])request.getParameterValues(name);
917
918 6799 cjones
                if (name.equals("fromDate") && value != null)
919 6264 leinfelder
                {
920 6273 leinfelder
                    try
921 6264 leinfelder
                    {
922 6273 leinfelder
                      //startTime = dateFormat.parse(value[0]);
923 6469 leinfelder
                    	startTime = DateTimeMarshaller.deserializeDateToUTC(value[0]);
924
                        //startTime = parseDateAndConvertToGMT(value[0]);
925 6264 leinfelder
                    }
926 6273 leinfelder
                    catch(Exception e)
927 6799 cjones
                    {  //if we can't parse it, just don't use the fromDate param
928
                        logMetacat.warn("Could not parse fromDate: " + value[0]);
929 6273 leinfelder
                        startTime = null;
930 6264 leinfelder
                    }
931 6273 leinfelder
                }
932 6799 cjones
                else if(name.equals("toDate") && value != null)
933 6273 leinfelder
                {
934
                    try
935 6264 leinfelder
                    {
936 6469 leinfelder
                    	endTime = DateTimeMarshaller.deserializeDateToUTC(value[0]);
937 6264 leinfelder
                    }
938 6273 leinfelder
                    catch(Exception e)
939 6799 cjones
                    {  //if we can't parse it, just don't use the toDate param
940
                        logMetacat.warn("Could not parse toDate: " + value[0]);
941 6273 leinfelder
                        endTime = null;
942
                    }
943 6264 leinfelder
                }
944 7100 leinfelder
                else if(name.equals("formatId") && value != null)
945 6264 leinfelder
                {
946 7100 leinfelder
                	formatId = new ObjectFormatIdentifier();
947
                	formatId.setValue(value[0]);
948 6264 leinfelder
                }
949 6273 leinfelder
                else if(name.equals("replicaStatus") && value != null)
950 6264 leinfelder
                {
951 6273 leinfelder
                    if(value != null &&
952
                       value.length > 0 &&
953
                       (value[0].equals("true") || value[0].equals("TRUE") || value[0].equals("YES")))
954
                    {
955
                        replicaStatus = true;
956
                    }
957 6264 leinfelder
                }
958 6273 leinfelder
                else if(name.equals("start") && value != null)
959 6264 leinfelder
                {
960 6273 leinfelder
                    start = new Integer(value[0]).intValue();
961 6264 leinfelder
                }
962 6273 leinfelder
                else if(name.equals("count") && value != null)
963 6264 leinfelder
                {
964 6273 leinfelder
                    count = new Integer(value[0]).intValue();
965 6264 leinfelder
                }
966
            }
967 6273 leinfelder
            //make the crud call
968
            logMetacat.debug("session: " + session + " startTime: " + startTime +
969 7100 leinfelder
                    " endTime: " + endTime + " formatId: " +
970
                    formatId + " replicaStatus: " + replicaStatus +
971 6273 leinfelder
                    " start: " + start + " count: " + count);
972
973
            ObjectList ol =
974 6542 leinfelder
           	 MNodeService.getInstance(request).listObjects(session, startTime, endTime,
975 7100 leinfelder
           			formatId, replicaStatus, start, count);
976 6352 cjones
977 6273 leinfelder
            out = response.getOutputStream();
978
            response.setStatus(200);
979
            response.setContentType("text/xml");
980
            // Serialize and write it to the output stream
981 6367 leinfelder
            TypeMarshaller.marshalTypeToOutputStream(ol, out);
982 6273 leinfelder
983 6264 leinfelder
        }
984 6273 leinfelder
985 6264 leinfelder
    }
986
987 6273 leinfelder
988 6264 leinfelder
    /**
989 6273 leinfelder
     * Retrieve System Metadata
990 6285 cjones
     * @param pid
991 6273 leinfelder
     * @throws InvalidToken
992
     * @throws ServiceFailure
993
     * @throws NotAuthorized
994
     * @throws NotFound
995
     * @throws InvalidRequest
996
     * @throws NotImplemented
997
     * @throws IOException
998
     * @throws JiBXException
999 6264 leinfelder
     */
1000 6285 cjones
    protected void getSystemMetadataObject(String pid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, InvalidRequest, NotImplemented, IOException, JiBXException {
1001 6273 leinfelder
1002
        Identifier id = new Identifier();
1003 6285 cjones
        id.setValue(pid);
1004 6542 leinfelder
        SystemMetadata sysmeta = MNodeService.getInstance(request).getSystemMetadata(session, id);
1005 6273 leinfelder
1006
        response.setContentType("text/xml");
1007
        response.setStatus(200);
1008
        OutputStream out = response.getOutputStream();
1009
1010
        // Serialize and write it to the output stream
1011 6367 leinfelder
        TypeMarshaller.marshalTypeToOutputStream(sysmeta, out);
1012 6273 leinfelder
   }
1013 6264 leinfelder
1014
1015
    /**
1016
     * Inserts or updates the object
1017
     *
1018 6285 cjones
     * @param pid - ID of data object to be inserted or updated.  If action is update, the pid
1019 6264 leinfelder
     *               is the existing pid.  If insert, the pid is the new one
1020 6269 leinfelder
     * @throws InvalidRequest
1021
     * @throws ServiceFailure
1022
     * @throws JiBXException
1023
     * @throws NotImplemented
1024
     * @throws InvalidSystemMetadata
1025
     * @throws InsufficientResources
1026
     * @throws UnsupportedType
1027
     * @throws IdentifierNotUnique
1028
     * @throws NotAuthorized
1029
     * @throws InvalidToken
1030
     * @throws NotFound
1031 6273 leinfelder
     * @throws IOException
1032 6367 leinfelder
     * @throws IllegalAccessException
1033
     * @throws InstantiationException
1034 6264 leinfelder
     */
1035 6972 leinfelder
    protected void putObject(String trailingPid, String action) throws ServiceFailure, InvalidRequest, JiBXException, InvalidToken, NotAuthorized, IdentifierNotUnique, UnsupportedType, InsufficientResources, InvalidSystemMetadata, NotImplemented, NotFound, IOException, InstantiationException, IllegalAccessException {
1036
1037
    	// Read the incoming data from its Mime Multipart encoding
1038 6269 leinfelder
    	Map<String, File> files = collectMultipartFiles();
1039 6972 leinfelder
1040 6975 leinfelder
    	Identifier pid = new Identifier();
1041 6972 leinfelder
        if (trailingPid == null) {
1042 6975 leinfelder
	        // get the pid string from the body and set the value
1043
	        String pidString = multipartparams.get("pid").get(0);
1044 7051 cjones
	        if (pidString != null) {
1045
            pid.setValue(pidString);
1046
1047
          } else {
1048
              throw new InvalidRequest("1102", "The pid param must be included and contain the identifier.");
1049
1050
          }
1051 6972 leinfelder
        } else {
1052
        	// use the pid included in the URL
1053
        	pid.setValue(trailingPid);
1054
        }
1055
        logMetacat.debug("putObject with pid " + pid.getValue());
1056
        logMetacat.debug("Entering putObject: " + pid.getValue() + "/" + action);
1057
1058 6269 leinfelder
        InputStream object = null;
1059
        InputStream sysmeta = null;
1060
        File smFile = files.get("sysmeta");
1061
        sysmeta = new FileInputStream(smFile);
1062
        File objFile = files.get("object");
1063
        object = new FileInputStream(objFile);
1064
1065 6927 cjones
        // ensure we have the object bytes
1066
        if  ( objFile == null ) {
1067
            throw new InvalidRequest("1102", "The object param must contain the object bytes.");
1068
1069
        }
1070
1071
        // ensure we have the system metadata
1072
        if  ( smFile == null ) {
1073
            throw new InvalidRequest("1102", "The sysmeta param must contain the system metadata document.");
1074
1075
        }
1076
1077 6972 leinfelder
        response.setStatus(200);
1078
        response.setContentType("text/xml");
1079
        OutputStream out = response.getOutputStream();
1080
1081 6269 leinfelder
        if (action.equals(FUNCTION_NAME_INSERT)) {
1082
            // handle inserts
1083
            logMetacat.debug("Commence creation...");
1084 6367 leinfelder
            SystemMetadata smd = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysmeta);
1085 6264 leinfelder
1086 6972 leinfelder
            logMetacat.debug("creating object with pid " + pid.getValue());
1087
            Identifier rId = MNodeService.getInstance(request).create(session, pid, object, smd);
1088 6367 leinfelder
            TypeMarshaller.marshalTypeToOutputStream(rId, out);
1089 6264 leinfelder
1090 6269 leinfelder
        } else if (action.equals(FUNCTION_NAME_UPDATE)) {
1091
        	// handle updates
1092
1093
            // construct pids
1094 6972 leinfelder
            Identifier newPid = null;
1095 6269 leinfelder
            try {
1096
            	String newPidString = multipartparams.get("newPid").get(0);
1097 6975 leinfelder
            	newPid = new Identifier();
1098
            	newPid.setValue(newPidString);
1099 6269 leinfelder
            } catch (Exception e) {
1100 6972 leinfelder
				logMetacat.error("Could not get newPid from request");
1101 6269 leinfelder
			}
1102
            logMetacat.debug("Commence update...");
1103
1104
            // get the systemmetadata object
1105 6367 leinfelder
            SystemMetadata smd = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysmeta);
1106 6264 leinfelder
1107 6972 leinfelder
            Identifier rId = MNodeService.getInstance(request).update(session, pid, object, newPid, smd);
1108 6367 leinfelder
            TypeMarshaller.marshalTypeToOutputStream(rId, out);
1109 6269 leinfelder
        } else {
1110
            throw new InvalidRequest("1000", "Operation must be create or update.");
1111
        }
1112 6972 leinfelder
1113 6264 leinfelder
    }
1114
1115
    /**
1116
     * Handle delete
1117 6285 cjones
     * @param pid ID of data object to be deleted
1118 6264 leinfelder
     * @throws IOException
1119 6273 leinfelder
     * @throws InvalidRequest
1120
     * @throws NotImplemented
1121
     * @throws NotFound
1122
     * @throws NotAuthorized
1123
     * @throws ServiceFailure
1124
     * @throws InvalidToken
1125
     * @throws JiBXException
1126 6264 leinfelder
     */
1127 6285 cjones
    private void deleteObject(String pid) throws IOException, InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, InvalidRequest, JiBXException
1128 6264 leinfelder
    {
1129
1130
        OutputStream out = response.getOutputStream();
1131
        response.setStatus(200);
1132
        response.setContentType("text/xml");
1133
1134
        Identifier id = new Identifier();
1135 6285 cjones
        id.setValue(pid);
1136 6273 leinfelder
1137
        logMetacat.debug("Calling delete");
1138 6542 leinfelder
        MNodeService.getInstance(request).delete(session, id);
1139 6367 leinfelder
        TypeMarshaller.marshalTypeToOutputStream(id, out);
1140 6273 leinfelder
1141
    }
1142 6264 leinfelder
1143 6514 leinfelder
	protected SynchronizationFailed collectSynchronizationFailed() throws IOException, ServiceFailure, InvalidRequest, JiBXException, InstantiationException, IllegalAccessException, ParserConfigurationException, SAXException  {
1144
1145
		// Read the incoming data from its Mime Multipart encoding
1146
		logMetacat.debug("Disassembling MIME multipart form");
1147
		InputStream sf = null;
1148
1149
		// handle MMP inputs
1150
		File tmpDir = getTempDirectory();
1151
		logMetacat.debug("temp dir: " + tmpDir.getAbsolutePath());
1152
		MultipartRequestResolver mrr =
1153
			new MultipartRequestResolver(tmpDir.getAbsolutePath(), 1000000000, 0);
1154
		MultipartRequest mr = null;
1155
		try {
1156
			mr = mrr.resolveMultipart(request);
1157
		} catch (Exception e) {
1158
			throw new ServiceFailure("2161",
1159
					"Could not resolve multipart: " + e.getMessage());
1160
		}
1161
		logMetacat.debug("resolved multipart request");
1162
		Map<String, File> files = mr.getMultipartFiles();
1163
		if (files == null || files.keySet() == null) {
1164
			throw new InvalidRequest("2163",
1165
					"must have multipart file with name 'message'");
1166
		}
1167
		logMetacat.debug("got multipart files");
1168
1169
		multipartparams = mr.getMultipartParameters();
1170
1171
		File sfFile = files.get("message");
1172
		if (sfFile == null) {
1173
			throw new InvalidRequest("2163",
1174
					"Missing the required file-part 'message' from the multipart request.");
1175
		}
1176
		logMetacat.debug("sfFile: " + sfFile.getAbsolutePath());
1177
		sf = new FileInputStream(sfFile);
1178
1179
		SynchronizationFailed syncFailed = (SynchronizationFailed) ExceptionHandler.deserializeXml(sf, "Error deserializing exception");
1180
		return syncFailed;
1181
	}
1182
1183 6264 leinfelder
}