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