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
					throw new RuntimeException(e.getMessage(), e);
665
				}
666
			}
667
    	};
668
    	ExecutorService executor = Executors.newSingleThreadExecutor();
669
    	executor.execute(runner);
670
    	executor.shutdown();
671
672
    	// thread was started, so we return success
673 6678 cjones
        response.setStatus(200);
674 6679 leinfelder
675 6264 leinfelder
    }
676 6604 cjones
677 6264 leinfelder
    /**
678 6604 cjones
     * Handle the getReplica action for the MN
679
     * @param id  the identifier for the object
680
     * @throws NotFound
681
     * @throws ServiceFailure
682
     * @throws NotImplemented
683
     * @throws NotAuthorized
684
     * @throws InvalidToken
685
     * @throws InvalidRequest
686
     */
687
    private void getReplica(String id)
688
        throws InvalidRequest, InvalidToken, NotAuthorized, NotImplemented,
689
        ServiceFailure, NotFound {
690
691
        Identifier pid = new Identifier();
692
        pid.setValue(id);
693
        OutputStream out = null;
694
        InputStream dataBytes = null;
695
696
        try {
697
            // call the service
698
            dataBytes = MNodeService.getInstance(request).getReplica(session, pid);
699
700
            response.setContentType("application/octet-stream");
701
            response.setStatus(200);
702
            out = response.getOutputStream();
703
            // write the object to the output stream
704
            IOUtils.copyLarge(dataBytes, out);
705
706
        } catch (IOException e) {
707
            String msg = "There was an error writing the output: " + e.getMessage();
708
            logMetacat.error(msg);
709
            throw new ServiceFailure("2181", msg);
710
711
        }
712
713
    }
714
715
    /**
716 6264 leinfelder
     * Get the Node information
717
     *
718
     * @throws JiBXException
719
     * @throws IOException
720
     * @throws InvalidRequest
721
     * @throws ServiceFailure
722
     * @throws NotAuthorized
723
     * @throws NotImplemented
724
     */
725
    private void node()
726
        throws JiBXException, IOException, NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest {
727
728 6542 leinfelder
        Node n = MNodeService.getInstance(request).getCapabilities();
729 6264 leinfelder
730
        response.setContentType("text/xml");
731
        response.setStatus(200);
732 6501 leinfelder
        TypeMarshaller.marshalTypeToOutputStream(n, response.getOutputStream());
733 6264 leinfelder
734
    }
735
736
    /**
737
     * MN_crud.describe()
738
     * http://mule1.dataone.org/ArchitectureDocs/mn_api_crud.html#MN_crud.describe
739 6285 cjones
     * @param pid
740 6273 leinfelder
     * @throws InvalidRequest
741
     * @throws NotImplemented
742
     * @throws NotFound
743
     * @throws NotAuthorized
744
     * @throws ServiceFailure
745
     * @throws InvalidToken
746 6264 leinfelder
     */
747 6285 cjones
    private void describeObject(String pid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, InvalidRequest
748 6264 leinfelder
    {
749 7043 leinfelder
750 6264 leinfelder
        response.setContentType("text/xml");
751 7043 leinfelder
752 6264 leinfelder
        Identifier id = new Identifier();
753 6285 cjones
        id.setValue(pid);
754 6273 leinfelder
755 7043 leinfelder
        DescribeResponse dr = null;
756
        try {
757
        	dr = MNodeService.getInstance(request).describe(session, id);
758
        } catch (BaseException e) {
759
        	response.setStatus(e.getCode());
760
        	response.addHeader("DataONE-Exception-Name", e.getClass().getName());
761
            response.addHeader("DataONE-Exception-DetailCode", e.getDetail_code());
762
            response.addHeader("DataONE-Exception-Description", e.getDescription());
763
            response.addHeader("DataONE-Exception-PID", id.getValue());
764
            return;
765
		}
766
767
        response.setStatus(200);
768
769 6502 leinfelder
        //response.addHeader("pid", pid);
770 6507 leinfelder
        response.addHeader("DataONE-Checksum", dr.getDataONE_Checksum().getAlgorithm() + "," + dr.getDataONE_Checksum().getValue());
771 6502 leinfelder
        response.addHeader("Content-Length", dr.getContent_Length() + "");
772
        response.addHeader("Last-Modified", DateTimeMarshaller.serializeDateToUTC(dr.getLast_Modified()));
773 6691 leinfelder
        response.addHeader("DataONE-ObjectFormat", dr.getDataONE_ObjectFormatIdentifier().getValue());
774 6773 leinfelder
        response.addHeader("DataONE-SerialVersion", dr.getSerialVersion().toString());
775
776 6502 leinfelder
777 6264 leinfelder
    }
778
779
    /**
780
     * get the logs based on passed params.  Available
781
     * See http://mule1.dataone.org/ArchitectureDocs/mn_api_crud.html#MN_crud.getLogRecords
782
     * for more info
783 6273 leinfelder
     * @throws NotImplemented
784
     * @throws InvalidRequest
785
     * @throws NotAuthorized
786
     * @throws ServiceFailure
787
     * @throws InvalidToken
788
     * @throws IOException
789
     * @throws JiBXException
790 6264 leinfelder
     */
791 6273 leinfelder
    private void getLog() throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest, NotImplemented, IOException, JiBXException
792 6264 leinfelder
    {
793 6273 leinfelder
794
        Date fromDate = null;
795
        Date toDate = null;
796
        Event event = null;
797
        Integer start = null;
798
        Integer count = null;
799
800 6264 leinfelder
        try {
801 6273 leinfelder
        	String fromDateS = params.get("fromDate")[0];
802
            logMetacat.debug("param fromDateS: " + fromDateS);
803 6469 leinfelder
            fromDate = DateTimeMarshaller.deserializeDateToUTC(fromDateS);
804 6273 leinfelder
        } catch (Exception e) {
805
        	logMetacat.warn("Could not parse fromDate: " + e.getMessage());
806 6264 leinfelder
        }
807 6273 leinfelder
        try {
808
        	String toDateS = params.get("toDate")[0];
809
            logMetacat.debug("param toDateS: " + toDateS);
810 6469 leinfelder
            toDate = DateTimeMarshaller.deserializeDateToUTC(toDateS);
811 6273 leinfelder
        } catch (Exception e) {
812
        	logMetacat.warn("Could not parse toDate: " + e.getMessage());
813
		}
814
        try {
815
        	String eventS = params.get("event")[0];
816
            event = Event.convert(eventS);
817
        } catch (Exception e) {
818
        	logMetacat.warn("Could not parse event: " + e.getMessage());
819
		}
820
        logMetacat.debug("fromDate: " + fromDate + " toDate: " + toDate);
821
822
        try {
823
        	start =  Integer.parseInt(params.get("start")[0]);
824
        } catch (Exception e) {
825
			logMetacat.warn("Could not parse start: " + e.getMessage());
826
		}
827
        try {
828
        	count =  Integer.parseInt(params.get("count")[0]);
829
        } catch (Exception e) {
830
			logMetacat.warn("Could not parse count: " + e.getMessage());
831
		}
832
833
        logMetacat.debug("calling getLogRecords");
834 6542 leinfelder
        Log log = MNodeService.getInstance(request).getLogRecords(session, fromDate, toDate, event, start, count);
835 6273 leinfelder
836
        OutputStream out = response.getOutputStream();
837
        response.setStatus(200);
838
        response.setContentType("text/xml");
839
840 6367 leinfelder
        TypeMarshaller.marshalTypeToOutputStream(log, out);
841 6273 leinfelder
842 6264 leinfelder
    }
843
844
    /**
845
     * Implements REST version of DataONE CRUD API --> get
846 6285 cjones
     * @param pid ID of data object to be read
847 6273 leinfelder
     * @throws NotImplemented
848
     * @throws InvalidRequest
849
     * @throws NotFound
850
     * @throws NotAuthorized
851
     * @throws ServiceFailure
852
     * @throws InvalidToken
853
     * @throws IOException
854
     * @throws JiBXException
855 6264 leinfelder
     */
856 6285 cjones
    protected void getObject(String pid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, InvalidRequest, NotImplemented, IOException, JiBXException {
857 6264 leinfelder
        OutputStream out = null;
858 6273 leinfelder
859 6285 cjones
        if (pid != null) { //get a specific document
860 6273 leinfelder
            Identifier id = new Identifier();
861 6285 cjones
            id.setValue(pid);
862 6273 leinfelder
863 6542 leinfelder
            SystemMetadata sm = MNodeService.getInstance(request).getSystemMetadata(session, id);
864 6264 leinfelder
865 6273 leinfelder
            //set the content type
866 6561 leinfelder
            if (sm.getFormatId().getValue().trim().equals(
867
            		ObjectFormatCache.getInstance().getFormat("text/csv").getFormatId().getValue()))
868 6273 leinfelder
            {
869
                response.setContentType("text/csv");
870
                response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".csv");
871
            }
872 6561 leinfelder
            else if (sm.getFormatId().getValue().trim().equals(
873
            		ObjectFormatCache.getInstance().getFormat("text/plain").getFormatId().getValue()))
874 6273 leinfelder
            {
875
                response.setContentType("text/plain");
876
                response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".txt");
877
            }
878 6561 leinfelder
            else if (sm.getFormatId().getValue().trim().equals(
879
            		ObjectFormatCache.getInstance().getFormat("application/octet-stream").getFormatId().getValue()))
880 6273 leinfelder
            {
881
                response.setContentType("application/octet-stream");
882
            }
883
            else
884
            {
885
                response.setContentType("text/xml");
886
                response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".xml");
887
            }
888
889 6542 leinfelder
            InputStream data = MNodeService.getInstance(request).get(session, id);
890 6273 leinfelder
891
            out = response.getOutputStream();
892
            IOUtils.copyLarge(data, out);
893
894
        }
895
        else
896
        { //call listObjects with specified params
897
            Date startTime = null;
898
            Date endTime = null;
899
            ObjectFormat objectFormat = null;
900
            boolean replicaStatus = false;
901
            int start = 0;
902
            //TODO: make the max count into a const
903
            int count = 1000;
904
            Enumeration paramlist = request.getParameterNames();
905
            while (paramlist.hasMoreElements())
906
            { //parse the params and make the crud call
907
                String name = (String) paramlist.nextElement();
908
                String[] value = (String[])request.getParameterValues(name);
909
910 6799 cjones
                if (name.equals("fromDate") && value != null)
911 6264 leinfelder
                {
912 6273 leinfelder
                    try
913 6264 leinfelder
                    {
914 6273 leinfelder
                      //startTime = dateFormat.parse(value[0]);
915 6469 leinfelder
                    	startTime = DateTimeMarshaller.deserializeDateToUTC(value[0]);
916
                        //startTime = parseDateAndConvertToGMT(value[0]);
917 6264 leinfelder
                    }
918 6273 leinfelder
                    catch(Exception e)
919 6799 cjones
                    {  //if we can't parse it, just don't use the fromDate param
920
                        logMetacat.warn("Could not parse fromDate: " + value[0]);
921 6273 leinfelder
                        startTime = null;
922 6264 leinfelder
                    }
923 6273 leinfelder
                }
924 6799 cjones
                else if(name.equals("toDate") && value != null)
925 6273 leinfelder
                {
926
                    try
927 6264 leinfelder
                    {
928 6469 leinfelder
                    	endTime = DateTimeMarshaller.deserializeDateToUTC(value[0]);
929 6264 leinfelder
                    }
930 6273 leinfelder
                    catch(Exception e)
931 6799 cjones
                    {  //if we can't parse it, just don't use the toDate param
932
                        logMetacat.warn("Could not parse toDate: " + value[0]);
933 6273 leinfelder
                        endTime = null;
934
                    }
935 6264 leinfelder
                }
936 6273 leinfelder
                else if(name.equals("objectFormat") && value != null)
937 6264 leinfelder
                {
938 6273 leinfelder
                    objectFormat = ObjectFormatCache.getInstance().getFormat(value[0]);
939 6264 leinfelder
                }
940 6273 leinfelder
                else if(name.equals("replicaStatus") && value != null)
941 6264 leinfelder
                {
942 6273 leinfelder
                    if(value != null &&
943
                       value.length > 0 &&
944
                       (value[0].equals("true") || value[0].equals("TRUE") || value[0].equals("YES")))
945
                    {
946
                        replicaStatus = true;
947
                    }
948 6264 leinfelder
                }
949 6273 leinfelder
                else if(name.equals("start") && value != null)
950 6264 leinfelder
                {
951 6273 leinfelder
                    start = new Integer(value[0]).intValue();
952 6264 leinfelder
                }
953 6273 leinfelder
                else if(name.equals("count") && value != null)
954 6264 leinfelder
                {
955 6273 leinfelder
                    count = new Integer(value[0]).intValue();
956 6264 leinfelder
                }
957
            }
958 6273 leinfelder
            //make the crud call
959
            logMetacat.debug("session: " + session + " startTime: " + startTime +
960
                    " endtime: " + endTime + " objectFormat: " +
961
                    objectFormat + " replicaStatus: " + replicaStatus +
962
                    " start: " + start + " count: " + count);
963
964 6432 leinfelder
            ObjectFormatIdentifier fmtid = null;
965 6352 cjones
966
            if ( objectFormat != null ) {
967 6561 leinfelder
          	 fmtid = objectFormat.getFormatId();
968 6352 cjones
969
            }
970 6273 leinfelder
            ObjectList ol =
971 6542 leinfelder
           	 MNodeService.getInstance(request).listObjects(session, startTime, endTime,
972 6352 cjones
               fmtid, replicaStatus, start, count);
973
974 6273 leinfelder
            out = response.getOutputStream();
975
            response.setStatus(200);
976
            response.setContentType("text/xml");
977
            // Serialize and write it to the output stream
978 6367 leinfelder
            TypeMarshaller.marshalTypeToOutputStream(ol, out);
979 6273 leinfelder
980 6264 leinfelder
        }
981 6273 leinfelder
982 6264 leinfelder
    }
983
984 6273 leinfelder
985 6264 leinfelder
    /**
986 6273 leinfelder
     * Retrieve System Metadata
987 6285 cjones
     * @param pid
988 6273 leinfelder
     * @throws InvalidToken
989
     * @throws ServiceFailure
990
     * @throws NotAuthorized
991
     * @throws NotFound
992
     * @throws InvalidRequest
993
     * @throws NotImplemented
994
     * @throws IOException
995
     * @throws JiBXException
996 6264 leinfelder
     */
997 6285 cjones
    protected void getSystemMetadataObject(String pid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, InvalidRequest, NotImplemented, IOException, JiBXException {
998 6273 leinfelder
999
        Identifier id = new Identifier();
1000 6285 cjones
        id.setValue(pid);
1001 6542 leinfelder
        SystemMetadata sysmeta = MNodeService.getInstance(request).getSystemMetadata(session, id);
1002 6273 leinfelder
1003
        response.setContentType("text/xml");
1004
        response.setStatus(200);
1005
        OutputStream out = response.getOutputStream();
1006
1007
        // Serialize and write it to the output stream
1008 6367 leinfelder
        TypeMarshaller.marshalTypeToOutputStream(sysmeta, out);
1009 6273 leinfelder
   }
1010 6264 leinfelder
1011
1012
    /**
1013
     * Inserts or updates the object
1014
     *
1015 6285 cjones
     * @param pid - ID of data object to be inserted or updated.  If action is update, the pid
1016 6264 leinfelder
     *               is the existing pid.  If insert, the pid is the new one
1017 6269 leinfelder
     * @throws InvalidRequest
1018
     * @throws ServiceFailure
1019
     * @throws JiBXException
1020
     * @throws NotImplemented
1021
     * @throws InvalidSystemMetadata
1022
     * @throws InsufficientResources
1023
     * @throws UnsupportedType
1024
     * @throws IdentifierNotUnique
1025
     * @throws NotAuthorized
1026
     * @throws InvalidToken
1027
     * @throws NotFound
1028 6273 leinfelder
     * @throws IOException
1029 6367 leinfelder
     * @throws IllegalAccessException
1030
     * @throws InstantiationException
1031 6264 leinfelder
     */
1032 6972 leinfelder
    protected void putObject(String trailingPid, String action) throws ServiceFailure, InvalidRequest, JiBXException, InvalidToken, NotAuthorized, IdentifierNotUnique, UnsupportedType, InsufficientResources, InvalidSystemMetadata, NotImplemented, NotFound, IOException, InstantiationException, IllegalAccessException {
1033
1034
    	// Read the incoming data from its Mime Multipart encoding
1035 6269 leinfelder
    	Map<String, File> files = collectMultipartFiles();
1036 6972 leinfelder
1037 6975 leinfelder
    	Identifier pid = new Identifier();
1038 6972 leinfelder
        if (trailingPid == null) {
1039 6975 leinfelder
	        // get the pid string from the body and set the value
1040
	        String pidString = multipartparams.get("pid").get(0);
1041 7051 cjones
	        if (pidString != null) {
1042
            pid.setValue(pidString);
1043
1044
          } else {
1045
              throw new InvalidRequest("1102", "The pid param must be included and contain the identifier.");
1046
1047
          }
1048 6972 leinfelder
        } else {
1049
        	// use the pid included in the URL
1050
        	pid.setValue(trailingPid);
1051
        }
1052
        logMetacat.debug("putObject with pid " + pid.getValue());
1053
        logMetacat.debug("Entering putObject: " + pid.getValue() + "/" + action);
1054
1055 6269 leinfelder
        InputStream object = null;
1056
        InputStream sysmeta = null;
1057
        File smFile = files.get("sysmeta");
1058
        sysmeta = new FileInputStream(smFile);
1059
        File objFile = files.get("object");
1060
        object = new FileInputStream(objFile);
1061
1062 6927 cjones
        // ensure we have the object bytes
1063
        if  ( objFile == null ) {
1064
            throw new InvalidRequest("1102", "The object param must contain the object bytes.");
1065
1066
        }
1067
1068
        // ensure we have the system metadata
1069
        if  ( smFile == null ) {
1070
            throw new InvalidRequest("1102", "The sysmeta param must contain the system metadata document.");
1071
1072
        }
1073
1074 6972 leinfelder
        response.setStatus(200);
1075
        response.setContentType("text/xml");
1076
        OutputStream out = response.getOutputStream();
1077
1078 6269 leinfelder
        if (action.equals(FUNCTION_NAME_INSERT)) {
1079
            // handle inserts
1080
            logMetacat.debug("Commence creation...");
1081 6367 leinfelder
            SystemMetadata smd = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysmeta);
1082 6264 leinfelder
1083 6972 leinfelder
            logMetacat.debug("creating object with pid " + pid.getValue());
1084
            Identifier rId = MNodeService.getInstance(request).create(session, pid, object, smd);
1085 6367 leinfelder
            TypeMarshaller.marshalTypeToOutputStream(rId, out);
1086 6264 leinfelder
1087 6269 leinfelder
        } else if (action.equals(FUNCTION_NAME_UPDATE)) {
1088
        	// handle updates
1089
1090
            // construct pids
1091 6972 leinfelder
            Identifier newPid = null;
1092 6269 leinfelder
            try {
1093
            	String newPidString = multipartparams.get("newPid").get(0);
1094 6975 leinfelder
            	newPid = new Identifier();
1095
            	newPid.setValue(newPidString);
1096 6269 leinfelder
            } catch (Exception e) {
1097 6972 leinfelder
				logMetacat.error("Could not get newPid from request");
1098 6269 leinfelder
			}
1099
            logMetacat.debug("Commence update...");
1100
1101
            // get the systemmetadata object
1102 6367 leinfelder
            SystemMetadata smd = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysmeta);
1103 6264 leinfelder
1104 6972 leinfelder
            Identifier rId = MNodeService.getInstance(request).update(session, pid, object, newPid, smd);
1105 6367 leinfelder
            TypeMarshaller.marshalTypeToOutputStream(rId, out);
1106 6269 leinfelder
        } else {
1107
            throw new InvalidRequest("1000", "Operation must be create or update.");
1108
        }
1109 6972 leinfelder
1110 6264 leinfelder
    }
1111
1112
    /**
1113
     * Handle delete
1114 6285 cjones
     * @param pid ID of data object to be deleted
1115 6264 leinfelder
     * @throws IOException
1116 6273 leinfelder
     * @throws InvalidRequest
1117
     * @throws NotImplemented
1118
     * @throws NotFound
1119
     * @throws NotAuthorized
1120
     * @throws ServiceFailure
1121
     * @throws InvalidToken
1122
     * @throws JiBXException
1123 6264 leinfelder
     */
1124 6285 cjones
    private void deleteObject(String pid) throws IOException, InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, InvalidRequest, JiBXException
1125 6264 leinfelder
    {
1126
1127
        OutputStream out = response.getOutputStream();
1128
        response.setStatus(200);
1129
        response.setContentType("text/xml");
1130
1131
        Identifier id = new Identifier();
1132 6285 cjones
        id.setValue(pid);
1133 6273 leinfelder
1134
        logMetacat.debug("Calling delete");
1135 6542 leinfelder
        MNodeService.getInstance(request).delete(session, id);
1136 6367 leinfelder
        TypeMarshaller.marshalTypeToOutputStream(id, out);
1137 6273 leinfelder
1138
    }
1139 6264 leinfelder
1140 6514 leinfelder
	protected SynchronizationFailed collectSynchronizationFailed() throws IOException, ServiceFailure, InvalidRequest, JiBXException, InstantiationException, IllegalAccessException, ParserConfigurationException, SAXException  {
1141
1142
		// Read the incoming data from its Mime Multipart encoding
1143
		logMetacat.debug("Disassembling MIME multipart form");
1144
		InputStream sf = null;
1145
1146
		// handle MMP inputs
1147
		File tmpDir = getTempDirectory();
1148
		logMetacat.debug("temp dir: " + tmpDir.getAbsolutePath());
1149
		MultipartRequestResolver mrr =
1150
			new MultipartRequestResolver(tmpDir.getAbsolutePath(), 1000000000, 0);
1151
		MultipartRequest mr = null;
1152
		try {
1153
			mr = mrr.resolveMultipart(request);
1154
		} catch (Exception e) {
1155
			throw new ServiceFailure("2161",
1156
					"Could not resolve multipart: " + e.getMessage());
1157
		}
1158
		logMetacat.debug("resolved multipart request");
1159
		Map<String, File> files = mr.getMultipartFiles();
1160
		if (files == null || files.keySet() == null) {
1161
			throw new InvalidRequest("2163",
1162
					"must have multipart file with name 'message'");
1163
		}
1164
		logMetacat.debug("got multipart files");
1165
1166
		multipartparams = mr.getMultipartParameters();
1167
1168
		File sfFile = files.get("message");
1169
		if (sfFile == null) {
1170
			throw new InvalidRequest("2163",
1171
					"Missing the required file-part 'message' from the multipart request.");
1172
		}
1173
		logMetacat.debug("sfFile: " + sfFile.getAbsolutePath());
1174
		sf = new FileInputStream(sfFile);
1175
1176
		SynchronizationFailed syncFailed = (SynchronizationFailed) ExceptionHandler.deserializeXml(sf, "Error deserializing exception");
1177
		return syncFailed;
1178
	}
1179
1180 6264 leinfelder
}