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 8810 leinfelder
package edu.ucsb.nceas.metacat.restservice.v2;
24 6264 leinfelder
25
import java.io.File;
26
import java.io.FileInputStream;
27 9122 tao
import java.io.FileNotFoundException;
28 6264 leinfelder
import java.io.IOException;
29
import java.io.InputStream;
30
import java.io.OutputStream;
31
import java.util.Date;
32
import java.util.Enumeration;
33 9235 leinfelder
import java.util.Iterator;
34 6264 leinfelder
import java.util.Map;
35 6679 leinfelder
import java.util.concurrent.ExecutorService;
36
import java.util.concurrent.Executors;
37 6264 leinfelder
38
import javax.servlet.ServletContext;
39
import javax.servlet.http.HttpServletRequest;
40
import javax.servlet.http.HttpServletResponse;
41 6472 leinfelder
import javax.xml.parsers.ParserConfigurationException;
42 6264 leinfelder
43 6273 leinfelder
import org.apache.commons.fileupload.FileUploadException;
44 6264 leinfelder
import org.apache.commons.io.IOUtils;
45
import org.apache.log4j.Logger;
46 9235 leinfelder
import org.dataone.client.v2.formats.ObjectFormatCache;
47 8810 leinfelder
import org.dataone.client.v2.formats.ObjectFormatInfo;
48 9833 tao
import org.dataone.exceptions.MarshallingException;
49 6472 leinfelder
import org.dataone.mimemultipart.MultipartRequest;
50
import org.dataone.mimemultipart.MultipartRequestResolver;
51 8874 leinfelder
import org.dataone.portal.TokenGenerator;
52 6264 leinfelder
import org.dataone.service.exceptions.BaseException;
53
import org.dataone.service.exceptions.IdentifierNotUnique;
54
import org.dataone.service.exceptions.InsufficientResources;
55
import org.dataone.service.exceptions.InvalidRequest;
56
import org.dataone.service.exceptions.InvalidSystemMetadata;
57
import org.dataone.service.exceptions.InvalidToken;
58
import org.dataone.service.exceptions.NotAuthorized;
59
import org.dataone.service.exceptions.NotFound;
60
import org.dataone.service.exceptions.NotImplemented;
61
import org.dataone.service.exceptions.ServiceFailure;
62
import org.dataone.service.exceptions.SynchronizationFailed;
63
import org.dataone.service.exceptions.UnsupportedType;
64 6366 leinfelder
import org.dataone.service.types.v1.Checksum;
65
import org.dataone.service.types.v1.DescribeResponse;
66
import org.dataone.service.types.v1.Identifier;
67
import org.dataone.service.types.v1.NodeReference;
68
import org.dataone.service.types.v1.ObjectFormatIdentifier;
69
import org.dataone.service.types.v1.ObjectList;
70
import org.dataone.service.types.v1.Permission;
71 9009 leinfelder
import org.dataone.service.types.v1.Person;
72 9173 leinfelder
import org.dataone.service.types.v1.Subject;
73
import org.dataone.service.types.v1.SubjectInfo;
74 7417 leinfelder
import org.dataone.service.types.v1_1.QueryEngineDescription;
75
import org.dataone.service.types.v1_1.QueryEngineList;
76 8874 leinfelder
import org.dataone.service.types.v2.Log;
77 9235 leinfelder
import org.dataone.service.types.v2.MediaType;
78
import org.dataone.service.types.v2.MediaTypeProperty;
79 8874 leinfelder
import org.dataone.service.types.v2.Node;
80 9244 leinfelder
import org.dataone.service.types.v2.ObjectFormat;
81 9148 tao
import org.dataone.service.types.v2.OptionList;
82 8874 leinfelder
import org.dataone.service.types.v2.SystemMetadata;
83 7019 leinfelder
import org.dataone.service.util.Constants;
84 6469 leinfelder
import org.dataone.service.util.DateTimeMarshaller;
85 6472 leinfelder
import org.dataone.service.util.ExceptionHandler;
86 6367 leinfelder
import org.dataone.service.util.TypeMarshaller;
87 6472 leinfelder
import org.xml.sax.SAXException;
88 6264 leinfelder
89 8874 leinfelder
import edu.ucsb.nceas.metacat.MetaCatServlet;
90 9479 tao
import edu.ucsb.nceas.metacat.ReadOnlyChecker;
91 7757 leinfelder
import edu.ucsb.nceas.metacat.common.query.stream.ContentTypeInputStream;
92 6264 leinfelder
import edu.ucsb.nceas.metacat.dataone.MNodeService;
93 6994 leinfelder
import edu.ucsb.nceas.metacat.properties.PropertyService;
94 8810 leinfelder
import edu.ucsb.nceas.metacat.restservice.D1ResourceHandler;
95 8160 leinfelder
import edu.ucsb.nceas.metacat.util.DeleteOnCloseFileInputStream;
96 6994 leinfelder
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
97 6264 leinfelder
98
/**
99
 * MN REST service implementation handler
100
 *
101
 * ******************
102
 * MNCore -- DONE
103
 * 		ping() - GET /d1/mn/monitor/ping
104
 * 		log() - GET /d1/mn/log
105
 * 		**getObjectStatistics() - GET /d1/mn/monitor/object
106
 * 		getOperationsStatistics - GET /d1/mn/monitor/event
107
 * 		**getStatus - GET /d1/mn/monitor/status
108
 * 		getCapabilities() - GET /d1/mn/ and /d1/mn/node
109
 *
110
 * 	MNRead -- DONE
111
 * 		get() - GET /d1/mn/object/PID
112
 * 		getSystemMetadata() - GET /d1/mn/meta/PID
113
 * 		describe() - HEAD /d1/mn/object/PID
114
 * 		getChecksum() - GET /d1/mn/checksum/PID
115
 * 		listObjects() - GET /d1/mn/object
116
 * 		synchronizationFailed() - POST /d1/mn/error
117
 *
118
 * 	MNAuthorization -- DONE
119
 * 		isAuthorized() - GET /d1/mn/isAuthorized/PID
120
 * 		setAccessPolicy() - PUT /d1/mn/accessRules/PID
121
 *
122 6297 cjones
 * 	MNStorage - DONE
123 6264 leinfelder
 * 		create() - POST /d1/mn/object/PID
124
 * 		update() - PUT /d1/mn/object/PID
125
 * 		delete() - DELETE /d1/mn/object/PID
126 7153 leinfelder
 * 		archive() - PUT /d1/mn/archive/PID
127 9122 tao
 *      updateSystemMetadata() - PUT /d1/mn/meta
128 7153 leinfelder
129 6619 cjones
 *    systemMetadataChanged() - POST /dirtySystemMetadata/PID
130 6264 leinfelder
 *
131
 * 	MNReplication
132
 * 		replicate() - POST /d1/mn/replicate
133 6604 cjones
 *    getReplica() - GET /d1/mn/replica
134 6264 leinfelder
 *
135
 * ******************
136
 * @author leinfelder
137
 *
138
 */
139 7417 leinfelder
public class MNResourceHandler extends D1ResourceHandler {
140 6264 leinfelder
141
    // MN-specific API Resources
142
    protected static final String RESOURCE_MONITOR = "monitor";
143
    protected static final String RESOURCE_REPLICATE = "replicate";
144 6604 cjones
    protected static final String RESOURCE_REPLICAS = "replica";
145 6264 leinfelder
    protected static final String RESOURCE_NODE = "node";
146
    protected static final String RESOURCE_ERROR = "error";
147 6619 cjones
    protected static final String RESOURCE_META_CHANGED = "dirtySystemMetadata";
148 7441 leinfelder
    protected static final String RESOURCE_GENERATE_ID = "generate";
149 7864 leinfelder
    protected static final String RESOURCE_PUBLISH = "publish";
150 9301 tao
    protected static final String RESOURCE_PACKAGE = "packages";
151 8874 leinfelder
    protected static final String RESOURCE_TOKEN = "token";
152 9173 leinfelder
    protected static final String RESOURCE_WHOAMI = "whoami";
153 7441 leinfelder
154 7861 leinfelder
155 8874 leinfelder
156 7143 leinfelder
157
    // shared executor
158
	private static ExecutorService executor = null;
159 6264 leinfelder
160 7143 leinfelder
	static {
161
		// use a shared executor service with nThreads == one less than available processors
162
    	int availableProcessors = Runtime.getRuntime().availableProcessors();
163
        int nThreads = availableProcessors * 1;
164
        nThreads--;
165 7183 leinfelder
        nThreads = Math.max(1, nThreads);
166 7143 leinfelder
    	executor = Executors.newFixedThreadPool(nThreads);
167
	}
168
169 6264 leinfelder
    /**
170
     * Initializes new instance by setting servlet context,request and response
171
     * */
172
    public MNResourceHandler(ServletContext servletContext,
173
            HttpServletRequest request, HttpServletResponse response) {
174
    	super(servletContext, request, response);
175
        logMetacat = Logger.getLogger(MNResourceHandler.class);
176
    }
177 6994 leinfelder
178
    @Override
179
    protected boolean isD1Enabled() {
180
181
    	boolean enabled = false;
182
    	try {
183
			enabled = Boolean.parseBoolean(PropertyService.getProperty("dataone.mn.services.enabled"));
184
		} catch (PropertyNotFoundException e) {
185
			logMetacat.error("Could not check if DataONE is enabled: " + e.getMessage());
186
		}
187
188
    	return enabled;
189
    }
190 6264 leinfelder
191
    /**
192 6271 leinfelder
     * This function is called from REST API servlet and handles each request to the servlet
193 6264 leinfelder
     *
194
     * @param httpVerb (GET, POST, PUT or DELETE)
195
     */
196 6271 leinfelder
    @Override
197 6264 leinfelder
    public void handle(byte httpVerb) {
198 6271 leinfelder
    	// prepare the handler
199
    	super.handle(httpVerb);
200
201 6264 leinfelder
        try {
202 6994 leinfelder
203
        	// only service requests if we have D1 configured
204
        	if (!isD1Enabled()) {
205
        		ServiceFailure se = new ServiceFailure("0000", "DataONE services are not enabled on this node");
206
                serializeException(se, response.getOutputStream());
207
                return;
208
        	}
209
210 6284 leinfelder
        	// get the resource
211
            String resource = request.getPathInfo();
212
            resource = resource.substring(resource.indexOf("/") + 1);
213 6264 leinfelder
214 6284 leinfelder
            // default to node info
215
            if (resource.equals("")) {
216 6264 leinfelder
                resource = RESOURCE_NODE;
217
            }
218 6284 leinfelder
219
            // get the rest of the path info
220
            String extra = null;
221 6264 leinfelder
222 6272 leinfelder
            logMetacat.debug("handling verb " + httpVerb + " request with resource '" + resource + "'");
223
            logMetacat.debug("resource: '" + resource + "'");
224 6264 leinfelder
            boolean status = false;
225
226
            if (resource != null) {
227
228 6284 leinfelder
                if (resource.startsWith(RESOURCE_NODE)) {
229 6264 leinfelder
                    // node response
230
                    node();
231
                    status = true;
232 8874 leinfelder
                } else if (resource.startsWith(RESOURCE_TOKEN)) {
233
                    logMetacat.debug("Using resource 'token'");
234
                    // get
235
                    if (httpVerb == GET) {
236
                    	// after the command
237
                        getToken();
238
                        status = true;
239
                    }
240
241 9173 leinfelder
                } else if (resource.startsWith(RESOURCE_WHOAMI)) {
242
                    logMetacat.debug("Using resource 'whoami'");
243
                    // get
244
                    if (httpVerb == GET) {
245
                    	// after the command
246
                        whoami();
247
                        status = true;
248
                    }
249
250 6284 leinfelder
                } else if (resource.startsWith(RESOURCE_IS_AUTHORIZED)) {
251 6264 leinfelder
                    if (httpVerb == GET) {
252 6514 leinfelder
                    	// after the command
253
                        extra = parseTrailing(resource, RESOURCE_IS_AUTHORIZED);
254 9300 tao
                        extra = decode(extra);
255 6264 leinfelder
	                	// check the access rules
256 6284 leinfelder
	                    isAuthorized(extra);
257 6264 leinfelder
	                    status = true;
258 6272 leinfelder
	                    logMetacat.debug("done getting access");
259 6264 leinfelder
                    }
260 6284 leinfelder
                } else if (resource.startsWith(RESOURCE_META)) {
261 6272 leinfelder
                    logMetacat.debug("Using resource 'meta'");
262 6264 leinfelder
                    // get
263
                    if (httpVerb == GET) {
264 9122 tao
                        logMetacat.debug("Using resource 'meta' for GET");
265 6514 leinfelder
                    	// after the command
266
                        extra = parseTrailing(resource, RESOURCE_META);
267 9300 tao
                        extra = decode(extra);
268 6284 leinfelder
                        getSystemMetadataObject(extra);
269 6264 leinfelder
                        status = true;
270 9122 tao
                    } else if (httpVerb == PUT) {
271
                        logMetacat.debug("Using resource 'meta' for PUT");
272
                        updateSystemMetadata();
273
                        status = true;
274 6264 leinfelder
                    }
275
276 6284 leinfelder
                } else if (resource.startsWith(RESOURCE_OBJECTS)) {
277 6272 leinfelder
                    logMetacat.debug("Using resource 'object'");
278 6514 leinfelder
                    // after the command
279
                    extra = parseTrailing(resource, RESOURCE_OBJECTS);
280 9300 tao
                    extra = decode(extra);
281 6284 leinfelder
                    logMetacat.debug("objectId: " + extra);
282 6264 leinfelder
                    logMetacat.debug("verb:" + httpVerb);
283
284
                    if (httpVerb == GET) {
285 6284 leinfelder
                        getObject(extra);
286 6264 leinfelder
                        status = true;
287
                    } else if (httpVerb == POST) {
288 6972 leinfelder
                    	// part of the params, not the URL
289
                        putObject(null, FUNCTION_NAME_INSERT);
290 6264 leinfelder
                        status = true;
291
                    } else if (httpVerb == PUT) {
292 6284 leinfelder
                        putObject(extra, FUNCTION_NAME_UPDATE);
293 6264 leinfelder
                        status = true;
294
                    } else if (httpVerb == DELETE) {
295 6284 leinfelder
                        deleteObject(extra);
296 6264 leinfelder
                        status = true;
297
                    } else if (httpVerb == HEAD) {
298 6284 leinfelder
                        describeObject(extra);
299 6264 leinfelder
                        status = true;
300
                    }
301
302 6284 leinfelder
                } else if (resource.startsWith(RESOURCE_LOG)) {
303 6272 leinfelder
                    logMetacat.debug("Using resource 'log'");
304 6264 leinfelder
                    // handle log events
305
                    if (httpVerb == GET) {
306
                        getLog();
307
                        status = true;
308
                    }
309 7153 leinfelder
                } else if (resource.startsWith(Constants.RESOURCE_ARCHIVE)) {
310
                    logMetacat.debug("Using resource " + Constants.RESOURCE_ARCHIVE);
311
                    // handle archive events
312
                    if (httpVerb == PUT) {
313
                        extra = parseTrailing(resource, Constants.RESOURCE_ARCHIVE);
314 9300 tao
                        extra = decode(extra);
315 7153 leinfelder
                        archive(extra);
316
                        status = true;
317
                    }
318 7019 leinfelder
                } else if (resource.startsWith(Constants.RESOURCE_CHECKSUM)) {
319 6272 leinfelder
                    logMetacat.debug("Using resource 'checksum'");
320 6264 leinfelder
                    // handle checksum requests
321
                    if (httpVerb == GET) {
322 6514 leinfelder
                    	// after the command
323 7019 leinfelder
                        extra = parseTrailing(resource, Constants.RESOURCE_CHECKSUM);
324 9300 tao
                        extra = decode(extra);
325 6284 leinfelder
                        checksum(extra);
326 6264 leinfelder
                        status = true;
327
                    }
328
                } else if (resource.startsWith(RESOURCE_MONITOR)) {
329
                    // there are various parts to monitoring
330
                    if (httpVerb == GET) {
331 6514 leinfelder
                    	// after the command
332
                        extra = parseTrailing(resource, RESOURCE_MONITOR);
333 9300 tao
                        extra = decode(extra);
334 6803 leinfelder
                        // ping
335
                        if (extra.toLowerCase().equals("ping")) {
336
                            logMetacat.debug("processing ping request");
337
                            Date result = MNodeService.getInstance(request).ping();
338
                            // TODO: send to output
339
                            status = true;
340
341
                        }
342
343 6264 leinfelder
                    }
344 6284 leinfelder
                } else if (resource.startsWith(RESOURCE_REPLICATE)) {
345 6264 leinfelder
                	if (httpVerb == POST) {
346 6272 leinfelder
	                    logMetacat.debug("processing replicate request");
347 6264 leinfelder
	                    replicate();
348
	                    status = true;
349
                	}
350 6284 leinfelder
                } else if (resource.startsWith(RESOURCE_ERROR)) {
351 6264 leinfelder
	                // sync error
352
	                if (httpVerb == POST) {
353
	                    syncError();
354
	                    status = true;
355
	                }
356 6604 cjones
                } else if (resource.startsWith(RESOURCE_META_CHANGED)) {
357
                    // system metadata changed
358
                    if (httpVerb == POST) {
359 6650 leinfelder
                        systemMetadataChanged();
360 6604 cjones
                        status = true;
361
                    }
362
                } else if (resource.startsWith(RESOURCE_REPLICAS)) {
363
                    // get replica
364
                    if (httpVerb == GET) {
365
                        extra = parseTrailing(resource, RESOURCE_REPLICAS);
366 9300 tao
                        extra = decode(extra);
367 6604 cjones
                        getReplica(extra);
368
                        status = true;
369
                    }
370 7417 leinfelder
                } else if (resource.startsWith(RESOURCE_QUERY)) {
371
	                logMetacat.debug("Using resource " + RESOURCE_QUERY);
372
	                // after the command
373
	                extra = parseTrailing(resource, RESOURCE_QUERY);
374
	                logMetacat.debug("query extra: " + extra);
375
376
	                String engine = null;
377
	                String query = null;
378
379
	                if (extra != null) {
380
		                // get the engine
381
		                int engineIndex = extra.length();
382
		                if (extra.indexOf("/") > -1) {
383
		                	engineIndex = extra.indexOf("/");
384
		                }
385
		                engine = extra.substring(0, engineIndex);
386 9300 tao
		                engine = decode(engine);
387 7417 leinfelder
		                logMetacat.debug("query engine: " + engine);
388
389 9333 leinfelder
		                // check the query string first
390
		                query = request.getQueryString();
391
392
		                // if null, look at the whole endpoint
393
		                if (query == null) {
394
			                // get the query if it is there
395
			                query = extra.substring(engineIndex, extra.length());
396
			                if (query != null && query.length() == 0) {
397
			                	query = null;
398
			                } else {
399
			                	if (query.startsWith("/")) {
400
			                		query = query.substring(1);
401
			                    }
402
			                }
403 7417 leinfelder
		                }
404 9333 leinfelder
405 9300 tao
		                query = decode(query);
406 7417 leinfelder
		                logMetacat.debug("query: " + query);
407
408
	                }
409
	                logMetacat.debug("verb:" + httpVerb);
410
	                if (httpVerb == GET) {
411
	                    doQuery(engine, query);
412
	                    status = true;
413
	                }
414 7441 leinfelder
                } else if (resource.startsWith(RESOURCE_GENERATE_ID)) {
415
                	// generate an id
416
                    if (httpVerb == POST) {
417
                        generateIdentifier();
418
                        status = true;
419
                    }
420 7864 leinfelder
                } else if (resource.startsWith(RESOURCE_PUBLISH)) {
421
                    logMetacat.debug("Using resource: " + RESOURCE_PUBLISH);
422
                    // PUT
423
                    if (httpVerb == PUT) {
424
                    	// after the command
425
                        extra = parseTrailing(resource, RESOURCE_PUBLISH);
426 9300 tao
                        extra = decode(extra);
427 7864 leinfelder
                        publish(extra);
428
                        status = true;
429
                    }
430 7855 leinfelder
                } else if (resource.startsWith(RESOURCE_PACKAGE)) {
431
                    logMetacat.debug("Using resource: " + RESOURCE_PACKAGE);
432 8810 leinfelder
                    // after the command
433
                    extra = parseTrailing(resource, RESOURCE_PACKAGE);
434
435
                    String format = null;
436
	                String pid = null;
437
438
	                if (extra != null) {
439
		                // get the format
440
		                int formatIndex = extra.length();
441
		                if (extra.indexOf("/") > -1) {
442
		                	formatIndex = extra.indexOf("/");
443
		                }
444
		                format = extra.substring(0, formatIndex);
445 9300 tao
		                format = decode(format);
446 8810 leinfelder
		                logMetacat.debug("package format: " + format);
447
448
		                // get the pid if it is there
449
		                pid = extra.substring(formatIndex, extra.length());
450
		                if (pid != null && pid.length() == 0) {
451
		                	pid = null;
452
		                } else {
453
		                	if (pid.startsWith("/")) {
454
		                		pid = pid.substring(1);
455
		                    }
456
		                }
457 9300 tao
		                pid = decode(pid);
458 8810 leinfelder
		                logMetacat.debug("pid: " + pid);
459
460
	                }
461
462 7855 leinfelder
                    // get
463
                    if (httpVerb == GET) {
464 8810 leinfelder
465
                        getPackage(format, pid);
466 7855 leinfelder
                        status = true;
467 7861 leinfelder
                    }
468
                } else if (resource.startsWith(RESOURCE_VIEWS)) {
469
	                logMetacat.debug("Using resource " + RESOURCE_VIEWS);
470
	                // after the command
471
	                extra = parseTrailing(resource, RESOURCE_VIEWS);
472
	                logMetacat.debug("view extra: " + extra);
473
474
	                String format = null;
475
	                String pid = null;
476
477
	                if (extra != null) {
478
		                // get the format
479
		                int formatIndex = extra.length();
480
		                if (extra.indexOf("/") > -1) {
481
		                	formatIndex = extra.indexOf("/");
482
		                }
483
		                format = extra.substring(0, formatIndex);
484 9300 tao
		                format = decode(format);
485 7861 leinfelder
		                logMetacat.debug("view format: " + format);
486
487
		                // get the pid if it is there
488
		                pid = extra.substring(formatIndex, extra.length());
489
		                if (pid != null && pid.length() == 0) {
490
		                	pid = null;
491
		                } else {
492
		                	if (pid.startsWith("/")) {
493
		                		pid = pid.substring(1);
494
		                    }
495
		                }
496 9300 tao
		                pid = decode(pid);
497 7861 leinfelder
		                logMetacat.debug("pid: " + pid);
498
499
	                }
500
	                logMetacat.debug("verb:" + httpVerb);
501
	                if (httpVerb == GET) {
502
	                    doViews(format, pid);
503
	                    status = true;
504
	                }
505 9301 tao
                } else {
506
                    throw new InvalidRequest("0000", "No resource matched for " + resource);
507
                }
508 6264 leinfelder
509
                if (!status) {
510 6273 leinfelder
                	throw new ServiceFailure("0000", "Unknown error, status = " + status);
511 6264 leinfelder
                }
512
            } else {
513 6273 leinfelder
            	throw new InvalidRequest("0000", "No resource matched for " + resource);
514 6264 leinfelder
            }
515
        } catch (BaseException be) {
516
        	// report Exceptions as clearly as possible
517
        	OutputStream out = null;
518
			try {
519
				out = response.getOutputStream();
520
			} catch (IOException e) {
521
				logMetacat.error("Could not get output stream from response", e);
522
			}
523
            serializeException(be, out);
524
        } catch (Exception e) {
525 6273 leinfelder
            // report Exceptions as clearly and generically as possible
526
            logMetacat.error(e.getClass() + ": " + e.getMessage(), e);
527
        	OutputStream out = null;
528
			try {
529
				out = response.getOutputStream();
530
			} catch (IOException ioe) {
531
				logMetacat.error("Could not get output stream from response", ioe);
532
			}
533
			ServiceFailure se = new ServiceFailure("0000", e.getMessage());
534
            serializeException(se, out);
535 6264 leinfelder
        }
536
    }
537
538 6604 cjones
539 7417 leinfelder
    private void doQuery(String engine, String query) {
540
541
		OutputStream out = null;
542
543
    	try {
544
    		// NOTE: we set the session explicitly for the MNode instance since these methods do not provide a parameter
545
	    	if (engine == null) {
546
	    		// just looking for list of engines
547
	    		MNodeService mnode = MNodeService.getInstance(request);
548
    			mnode.setSession(session);
549 8810 leinfelder
	    		QueryEngineList qel = mnode.listQueryEngines(session);
550 7417 leinfelder
	    		response.setContentType("text/xml");
551
	            response.setStatus(200);
552
	            out = response.getOutputStream();
553
	            TypeMarshaller.marshalTypeToOutputStream(qel, out);
554
	            return;
555
	    	} else {
556
	    		if (query != null) {
557
	    			MNodeService mnode = MNodeService.getInstance(request);
558
	    			mnode.setSession(session);
559 8810 leinfelder
	    			InputStream stream = mnode.query(session, engine, query);
560 7417 leinfelder
561 7757 leinfelder
	    			// set the content-type if we have it from the implementation
562
	    			if (stream instanceof ContentTypeInputStream) {
563
		    			//response.setContentType("application/octet-stream");
564
		    			//response.setContentType("text/xml");
565
	    				response.setContentType(((ContentTypeInputStream) stream).getContentType());
566
	    			}
567 7417 leinfelder
	                response.setStatus(200);
568
	                out = response.getOutputStream();
569
	                // write the results to the output stream
570
	                IOUtils.copyLarge(stream, out);
571
	                return;
572
	    		} else {
573
	    			MNodeService mnode = MNodeService.getInstance(request);
574
	    			mnode.setSession(session);
575 8810 leinfelder
	    			QueryEngineDescription qed = mnode.getQueryEngineDescription(session, engine);
576 7417 leinfelder
	    			response.setContentType("text/xml");
577
		            response.setStatus(200);
578
		            out = response.getOutputStream();
579
		            TypeMarshaller.marshalTypeToOutputStream(qed, out);
580
		            return;
581
	    		}
582
	    	}
583
584
585
    	} catch (BaseException be) {
586
        	// report Exceptions as clearly as possible
587
			try {
588
				out = response.getOutputStream();
589
			} catch (IOException e) {
590
				logMetacat.error("Could not get output stream from response", e);
591
			}
592
            serializeException(be, out);
593
        } catch (Exception e) {
594
            // report Exceptions as clearly and generically as possible
595
            logMetacat.error(e.getClass() + ": " + e.getMessage(), e);
596
			try {
597
				out = response.getOutputStream();
598
			} catch (IOException ioe) {
599
				logMetacat.error("Could not get output stream from response", ioe);
600
			}
601
			ServiceFailure se = new ServiceFailure("0000", e.getMessage());
602
            serializeException(se, out);
603
        }
604
    }
605
606 7861 leinfelder
    private void doViews(String format, String pid) {
607
608
		OutputStream out = null;
609
		MNodeService mnode = MNodeService.getInstance(request);
610
611
    	try {
612
    		// get a list of views
613
    		if (pid != null) {
614
    			Identifier identifier = new Identifier();
615
    			identifier.setValue(pid);
616 8810 leinfelder
				InputStream stream = mnode.view(session, format, identifier);
617 7861 leinfelder
618
    			// set the content-type if we have it from the implementation
619
    			if (stream instanceof ContentTypeInputStream) {
620
    				response.setContentType(((ContentTypeInputStream) stream).getContentType());
621
    			}
622
                response.setStatus(200);
623
                out = response.getOutputStream();
624
                // write the results to the output stream
625
                IOUtils.copyLarge(stream, out);
626
                return;
627
    		} else {
628
    			// TODO: list the registered views
629 9148 tao
                //BaseException ni = new NotImplemented("9999", "MN.listViews() is not implemented at this node");
630
				//throw ni;
631
    		    OptionList list = mnode.listViews(session);
632
633
    	        response.setContentType("text/xml");
634
    	        response.setStatus(200);
635
    	        TypeMarshaller.marshalTypeToOutputStream(list, response.getOutputStream());
636 7861 leinfelder
    		}
637
638
639
    	} catch (BaseException be) {
640
        	// report Exceptions as clearly as possible
641
			try {
642
				out = response.getOutputStream();
643
			} catch (IOException e) {
644
				logMetacat.error("Could not get output stream from response", e);
645
			}
646
            serializeException(be, out);
647
        } catch (Exception e) {
648
            // report Exceptions as clearly and generically as possible
649
            logMetacat.error(e.getClass() + ": " + e.getMessage(), e);
650
			try {
651
				out = response.getOutputStream();
652
			} catch (IOException ioe) {
653
				logMetacat.error("Could not get output stream from response", ioe);
654
			}
655
			ServiceFailure se = new ServiceFailure("0000", e.getMessage());
656
            serializeException(se, out);
657
        }
658
    }
659 7417 leinfelder
660 6273 leinfelder
    /**
661 6604 cjones
     * Handles notification of system metadata changes for the given identifier
662
     *
663
     * @param id  the identifier for the object
664
     * @throws InvalidToken
665
     * @throws InvalidRequest
666
     * @throws NotAuthorized
667
     * @throws ServiceFailure
668
     * @throws NotImplemented
669
     */
670 6650 leinfelder
    private void systemMetadataChanged()
671 6604 cjones
        throws NotImplemented, ServiceFailure, NotAuthorized, InvalidRequest,
672
        InvalidToken {
673 9479 tao
674
        ReadOnlyChecker checker = new ReadOnlyChecker();
675
        boolean isReadOnlyMode = checker.isReadOnly();
676
        if(isReadOnlyMode) {
677 9481 tao
            throw new ServiceFailure("1333", ReadOnlyChecker.DATAONEERROR);
678 9479 tao
        }
679
680 9327 tao
        //final long serialVersion = 0L;
681 6604 cjones
        String serialVersionStr = null;
682
        String dateSysMetaLastModifiedStr = null;
683
684 6660 leinfelder
        // mkae sure we have the multipart params
685
        try {
686
			initMultipartParams();
687
		} catch (Exception e1) {
688
			throw new ServiceFailure("1333", "Could not collect the multipart params for the request");
689
		}
690
691 6650 leinfelder
        // get the pid
692 9327 tao
        String id = null;
693 6650 leinfelder
        try {
694 9327 tao
        	id = multipartparams.get("pid").get(0);
695 6650 leinfelder
        } catch (NullPointerException e) {
696
            String msg = "The 'pid' must be provided as a parameter and was not.";
697
            logMetacat.error(msg);
698
            throw new InvalidRequest("1334", msg);
699 9327 tao
        }
700
        final Identifier pid = new Identifier();
701
        pid.setValue(id);
702 6650 leinfelder
703 6604 cjones
        // get the serialVersion
704
        try {
705 6660 leinfelder
            serialVersionStr = multipartparams.get("serialVersion").get(0);
706 6604 cjones
        } catch (NullPointerException e) {
707
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
708
            logMetacat.error(msg);
709
            throw new InvalidRequest("1334", msg);
710
711 9327 tao
        }
712 6604 cjones
713 9327 tao
        final long serialVersion = (new Long(serialVersionStr)).longValue();
714
715 6604 cjones
        // get the dateSysMetaLastModified
716
        try {
717 6660 leinfelder
            dateSysMetaLastModifiedStr = multipartparams.get("dateSysMetaLastModified").get(0);
718 6604 cjones
719 9327 tao
720 6604 cjones
        } catch (NullPointerException e) {
721
            String msg =
722
                "The 'dateSysMetaLastModified' must be provided as a " +
723
                "parameter and was not, or was an invalid representation of the timestamp.";
724
            logMetacat.error(msg);
725
            throw new InvalidRequest("1334", msg);
726
727 9327 tao
        }
728
        final Date dateSysMetaLastModified = DateTimeMarshaller.deserializeDateToUTC(dateSysMetaLastModifiedStr);
729 6604 cjones
730 9349 leinfelder
        // check authorization before sending to implementation
731
        boolean authorized = MNodeService.getInstance(request).isAdminAuthorized(session);
732
        if (!authorized) {
733
        	String msg = "User is not authorized to call systemMetadataChanged";
734
            NotAuthorized failure = new NotAuthorized("1331", msg);
735
        	throw failure;
736
        }
737
738 9327 tao
        // run it in a thread to avoid connection timeout
739
        Runnable runner = new Runnable() {
740
            @Override
741
            public void run() {
742
                try {
743
                   // call the service
744
                    MNodeService.getInstance(request).systemMetadataChanged(session, pid, serialVersion, dateSysMetaLastModified);
745
                } catch (Exception e) {
746
                    logMetacat.error("Error running replication: " + e.getMessage(), e);
747
                    throw new RuntimeException(e.getMessage(), e);
748
                }
749
            }
750
        };
751
        // submit the task, and that's it
752
        executor.submit(runner);
753
754
        // thread was started, so we return success
755 6604 cjones
        response.setStatus(200);
756
    }
757 7441 leinfelder
758
    /**
759
     * Handles identifier generation calls
760
     *
761
     * @throws InvalidRequest
762
     * @throws NotImplemented
763
     * @throws NotAuthorized
764
     * @throws ServiceFailure
765
     * @throws InvalidToken
766
     * @throws IOException
767 9833 tao
     * @throws MarshallingException
768 7441 leinfelder
     */
769 9833 tao
    private void generateIdentifier() throws InvalidToken, ServiceFailure, NotAuthorized, NotImplemented, InvalidRequest, IOException, MarshallingException {
770 7441 leinfelder
771
        // make sure we have the multipart params
772
        try {
773
			initMultipartParams();
774
		} catch (Exception e1) {
775
			throw new ServiceFailure("1333", "Could not collect the multipart params for the request");
776
		}
777
778
        // get the scheme
779
		String scheme = null;
780
        try {
781
        	scheme = multipartparams.get("scheme").get(0);
782
        } catch (NullPointerException e) {
783
            String msg = "The 'scheme' parameter was not provided, using default";
784
            logMetacat.warn(msg);
785
        }
786
787
        // get the fragment
788
		String fragment = null;
789
        try {
790
        	fragment = multipartparams.get("fragment").get(0);
791
        } catch (NullPointerException e) {
792
            String msg = "The 'fragment' parameter was not provided, using default";
793
            logMetacat.warn(msg);
794
        }
795 6604 cjones
796 7441 leinfelder
        // call the service
797
        Identifier identifier = MNodeService.getInstance(request).generateIdentifier(session, scheme, fragment);
798
        response.setStatus(200);
799
        response.setContentType("text/xml");
800
        OutputStream out = response.getOutputStream();
801
        TypeMarshaller.marshalTypeToOutputStream(identifier, out);
802
    }
803
804 6604 cjones
    /**
805 6273 leinfelder
     * Checks the access policy
806
     * @param id
807
     * @return
808
     * @throws ServiceFailure
809
     * @throws InvalidToken
810
     * @throws NotFound
811
     * @throws NotAuthorized
812
     * @throws NotImplemented
813
     * @throws InvalidRequest
814
     */
815 6264 leinfelder
    private boolean isAuthorized(String id) throws ServiceFailure, InvalidToken, NotFound, NotAuthorized, NotImplemented, InvalidRequest {
816
		Identifier pid = new Identifier();
817
		pid.setValue(id);
818
		Permission permission = null;
819
		try {
820 6509 leinfelder
			String perm = params.get("action")[0];
821 6373 leinfelder
			permission = Permission.convert(perm);
822 6264 leinfelder
		} catch (Exception e) {
823
			logMetacat.warn("No permission specified");
824
		}
825 6542 leinfelder
		boolean result = MNodeService.getInstance(request).isAuthorized(session, pid, permission);
826 6264 leinfelder
		response.setStatus(200);
827
		response.setContentType("text/xml");
828
		return result;
829
    }
830
831 8874 leinfelder
    private void getToken() throws Exception {
832
833
		if (this.session != null) {
834
			String userId = this.session.getSubject().getValue();
835 9009 leinfelder
			String fullName = null;
836
			try {
837
				Person person = this.session.getSubjectInfo().getPerson(0);
838
				fullName = person.getGivenName(0) + " " + person.getFamilyName();
839
			} catch (Exception e) {
840
				logMetacat.warn(e.getMessage(), e);
841
			}
842
843 8874 leinfelder
			String token = null;
844 9164 leinfelder
			token = TokenGenerator.getInstance().getJWT(userId, fullName);
845 8874 leinfelder
846
			response.setStatus(200);
847
			response.setContentType("text/plain");
848
	        OutputStream out = response.getOutputStream();
849
	        out.write(token.getBytes(MetaCatServlet.DEFAULT_ENCODING));
850
	        out.close();
851
		} else {
852
			response.setStatus(401);
853
			response.setContentType("text/plain");
854
			OutputStream out = response.getOutputStream();
855
	        out.write("No session information found".getBytes(MetaCatServlet.DEFAULT_ENCODING));
856
	        out.close();
857
		}
858
859
    }
860
861 9173 leinfelder
    private void whoami() throws Exception {
862
863
		if (this.session != null) {
864
			Subject subject = this.session.getSubject();
865
			SubjectInfo subjectInfo = null;
866
			try {
867
				subjectInfo = this.session.getSubjectInfo();
868
			} catch (Exception e) {
869
				logMetacat.warn(e.getMessage(), e);
870
			}
871
872
			response.setStatus(200);
873
			response.setContentType("text/plain");
874
	        OutputStream out = response.getOutputStream();
875
876
	        if (subjectInfo != null) {
877
		        TypeMarshaller.marshalTypeToOutputStream(subjectInfo, out);
878
	        } else {
879
		        TypeMarshaller.marshalTypeToOutputStream(subject, out);
880
	        }
881
882
	        out.close();
883
		} else {
884
			response.setStatus(401);
885
			response.setContentType("text/plain");
886
			OutputStream out = response.getOutputStream();
887
	        out.write("No session information found".getBytes(MetaCatServlet.DEFAULT_ENCODING));
888
	        out.close();
889
		}
890
891
    }
892
893 6273 leinfelder
    /**
894
     * Processes failed synchronization message
895
     * @throws NotImplemented
896
     * @throws ServiceFailure
897
     * @throws NotAuthorized
898
     * @throws InvalidRequest
899 9833 tao
     * @throws MarshallingException
900 6367 leinfelder
     * @throws IllegalAccessException
901
     * @throws InstantiationException
902
     * @throws IOException
903 6273 leinfelder
     */
904 9833 tao
    private void syncError() throws NotImplemented, ServiceFailure, NotAuthorized, InvalidRequest, MarshallingException, IOException, InstantiationException, IllegalAccessException {
905 6264 leinfelder
    	SynchronizationFailed syncFailed = null;
906 6472 leinfelder
		try {
907
			syncFailed = collectSynchronizationFailed();
908
		} catch (ParserConfigurationException e) {
909
			throw new ServiceFailure("2161", e.getMessage());
910
		} catch (SAXException e) {
911
			throw new ServiceFailure("2161", e.getMessage());
912
		}
913
914 6542 leinfelder
		MNodeService.getInstance(request).synchronizationFailed(session, syncFailed);
915 6264 leinfelder
    }
916 6472 leinfelder
917 8810 leinfelder
	/**
918 6273 leinfelder
     * Calculate the checksum
919
     * @throws NotImplemented
920 9833 tao
     * @throws MarshallingException
921 6273 leinfelder
     * @throws IOException
922
     * @throws InvalidToken
923
     * @throws ServiceFailure
924
     * @throws NotAuthorized
925
     * @throws NotFound
926
     * @throws InvalidRequest
927
     */
928 9833 tao
    private void checksum(String pid) throws NotImplemented, MarshallingException, IOException, InvalidToken, ServiceFailure, NotAuthorized, NotFound, InvalidRequest {
929 6264 leinfelder
    	String checksumAlgorithm = "MD5";
930 7222 leinfelder
    	try {
931
    		checksumAlgorithm = PropertyService.getProperty("dataone.checksumAlgorithm.default");
932
        } catch(Exception e) {
933
        	logMetacat.warn("Could not lookup configured default checksum algorithm, using: " + checksumAlgorithm);
934
        }
935 6284 leinfelder
936 6285 cjones
        Identifier pidid = new Identifier();
937
        pidid.setValue(pid);
938 6264 leinfelder
        try {
939
            checksumAlgorithm = params.get("checksumAlgorithm")[0];
940
        } catch(Exception e) {
941 7222 leinfelder
            //do nothing.  use the default
942 6264 leinfelder
        	logMetacat.warn("No algorithm specified, using default: " + checksumAlgorithm);
943
        }
944 6285 cjones
        logMetacat.debug("getting checksum for object " + pid + " with algorithm " + checksumAlgorithm);
945 6273 leinfelder
946 6542 leinfelder
        Checksum c = MNodeService.getInstance(request).getChecksum(session, pidid, checksumAlgorithm);
947 6273 leinfelder
        logMetacat.debug("got checksum " + c.getValue());
948
        response.setStatus(200);
949
        logMetacat.debug("serializing response");
950 6367 leinfelder
        TypeMarshaller.marshalTypeToOutputStream(c, response.getOutputStream());
951 6273 leinfelder
        logMetacat.debug("done serializing response.");
952
953 6264 leinfelder
    }
954
955
	/**
956
     * handle the replicate action for MN
957 9833 tao
	 * @throws MarshallingException
958 6273 leinfelder
	 * @throws FileUploadException
959
	 * @throws IOException
960
	 * @throws InvalidRequest
961
	 * @throws ServiceFailure
962
	 * @throws UnsupportedType
963
	 * @throws InsufficientResources
964
	 * @throws NotAuthorized
965
	 * @throws NotImplemented
966 6367 leinfelder
	 * @throws IllegalAccessException
967
	 * @throws InstantiationException
968 7142 leinfelder
	 * @throws InvalidToken
969 6264 leinfelder
     */
970 6678 cjones
    private void replicate()
971
        throws ServiceFailure, InvalidRequest, IOException, FileUploadException,
972 9833 tao
        MarshallingException, NotImplemented, NotAuthorized, InsufficientResources,
973 7142 leinfelder
        UnsupportedType, InstantiationException, IllegalAccessException, InvalidToken {
974 6264 leinfelder
975 6272 leinfelder
        logMetacat.debug("in POST replicate()");
976 9480 tao
        ReadOnlyChecker checker = new ReadOnlyChecker();
977
        boolean isReadOnlyMode = checker.isReadOnly();
978
        if(isReadOnlyMode) {
979 9481 tao
            throw new ServiceFailure("2151", ReadOnlyChecker.DATAONEERROR);
980 9480 tao
        }
981 6264 leinfelder
982 7064 leinfelder
        // somewhat unorthodox, but the call is asynchronous and we'd like to return this info sooner
983 7142 leinfelder
        boolean allowed = false;
984 7064 leinfelder
        if (session == null) {
985
        	String msg = "No session was provided.";
986
            NotAuthorized failure = new NotAuthorized("2152", msg);
987
        	throw failure;
988 7142 leinfelder
        } else {
989
        	allowed = MNodeService.getInstance(request).isAdminAuthorized(session);
990
        	if (!allowed) {
991
        		String msg = "User is not an admin user";
992
                NotAuthorized failure = new NotAuthorized("2152", msg);
993
            	throw failure;
994
        	}
995 7064 leinfelder
        }
996
997 8810 leinfelder
        // parse the systemMetadata
998
        Map<String, File> files = collectMultipartFiles();
999
        final SystemMetadata sysmeta = TypeMarshaller.unmarshalTypeFromFile(SystemMetadata.class, files.get("sysmeta"));
1000 6264 leinfelder
1001 6273 leinfelder
        String sn = multipartparams.get("sourceNode").get(0);
1002 6272 leinfelder
        logMetacat.debug("sourceNode: " + sn);
1003 6679 leinfelder
        final NodeReference sourceNode = new NodeReference();
1004 6548 cjones
        sourceNode.setValue(sn);
1005 6679 leinfelder
1006
        // run it in a thread to avoid connection timeout
1007
        Runnable runner = new Runnable() {
1008
			@Override
1009
			public void run() {
1010
				try {
1011
			        MNodeService.getInstance(request).replicate(session, sysmeta, sourceNode);
1012
				} catch (Exception e) {
1013 7091 leinfelder
					logMetacat.error("Error running replication: " + e.getMessage(), e);
1014 6679 leinfelder
					throw new RuntimeException(e.getMessage(), e);
1015
				}
1016
			}
1017
    	};
1018 7143 leinfelder
    	// submit the task, and that's it
1019
    	executor.submit(runner);
1020 6679 leinfelder
1021
    	// thread was started, so we return success
1022 6678 cjones
        response.setStatus(200);
1023 6679 leinfelder
1024 6264 leinfelder
    }
1025 6604 cjones
1026 6264 leinfelder
    /**
1027 6604 cjones
     * Handle the getReplica action for the MN
1028
     * @param id  the identifier for the object
1029
     * @throws NotFound
1030
     * @throws ServiceFailure
1031
     * @throws NotImplemented
1032
     * @throws NotAuthorized
1033
     * @throws InvalidToken
1034
     * @throws InvalidRequest
1035
     */
1036
    private void getReplica(String id)
1037
        throws InvalidRequest, InvalidToken, NotAuthorized, NotImplemented,
1038
        ServiceFailure, NotFound {
1039
1040
        Identifier pid = new Identifier();
1041
        pid.setValue(id);
1042
        OutputStream out = null;
1043
        InputStream dataBytes = null;
1044
1045
        try {
1046
            // call the service
1047
            dataBytes = MNodeService.getInstance(request).getReplica(session, pid);
1048
1049
            response.setContentType("application/octet-stream");
1050
            response.setStatus(200);
1051
            out = response.getOutputStream();
1052
            // write the object to the output stream
1053
            IOUtils.copyLarge(dataBytes, out);
1054
1055
        } catch (IOException e) {
1056
            String msg = "There was an error writing the output: " + e.getMessage();
1057
            logMetacat.error(msg);
1058
            throw new ServiceFailure("2181", msg);
1059
1060
        }
1061
1062
    }
1063
1064
    /**
1065 6264 leinfelder
     * Get the Node information
1066
     *
1067 9833 tao
     * @throws MarshallingException
1068 6264 leinfelder
     * @throws IOException
1069
     * @throws InvalidRequest
1070
     * @throws ServiceFailure
1071
     * @throws NotAuthorized
1072
     * @throws NotImplemented
1073
     */
1074
    private void node()
1075 9833 tao
        throws MarshallingException, IOException, NotImplemented, NotAuthorized, ServiceFailure, InvalidRequest {
1076 6264 leinfelder
1077 6542 leinfelder
        Node n = MNodeService.getInstance(request).getCapabilities();
1078 6264 leinfelder
1079
        response.setContentType("text/xml");
1080
        response.setStatus(200);
1081 6501 leinfelder
        TypeMarshaller.marshalTypeToOutputStream(n, response.getOutputStream());
1082 6264 leinfelder
1083
    }
1084
1085
    /**
1086
     * MN_crud.describe()
1087
     * http://mule1.dataone.org/ArchitectureDocs/mn_api_crud.html#MN_crud.describe
1088 6285 cjones
     * @param pid
1089 6273 leinfelder
     * @throws InvalidRequest
1090
     * @throws NotImplemented
1091
     * @throws NotFound
1092
     * @throws NotAuthorized
1093
     * @throws ServiceFailure
1094
     * @throws InvalidToken
1095 6264 leinfelder
     */
1096 6285 cjones
    private void describeObject(String pid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, InvalidRequest
1097 6264 leinfelder
    {
1098 7043 leinfelder
1099 6264 leinfelder
        response.setContentType("text/xml");
1100 7043 leinfelder
1101 6264 leinfelder
        Identifier id = new Identifier();
1102 6285 cjones
        id.setValue(pid);
1103 6273 leinfelder
1104 7043 leinfelder
        DescribeResponse dr = null;
1105
        try {
1106
        	dr = MNodeService.getInstance(request).describe(session, id);
1107
        } catch (BaseException e) {
1108
        	response.setStatus(e.getCode());
1109
        	response.addHeader("DataONE-Exception-Name", e.getClass().getName());
1110
            response.addHeader("DataONE-Exception-DetailCode", e.getDetail_code());
1111
            response.addHeader("DataONE-Exception-Description", e.getDescription());
1112
            response.addHeader("DataONE-Exception-PID", id.getValue());
1113
            return;
1114
		}
1115
1116
        response.setStatus(200);
1117
1118 6502 leinfelder
        //response.addHeader("pid", pid);
1119 6507 leinfelder
        response.addHeader("DataONE-Checksum", dr.getDataONE_Checksum().getAlgorithm() + "," + dr.getDataONE_Checksum().getValue());
1120 6502 leinfelder
        response.addHeader("Content-Length", dr.getContent_Length() + "");
1121
        response.addHeader("Last-Modified", DateTimeMarshaller.serializeDateToUTC(dr.getLast_Modified()));
1122 6691 leinfelder
        response.addHeader("DataONE-ObjectFormat", dr.getDataONE_ObjectFormatIdentifier().getValue());
1123 6773 leinfelder
        response.addHeader("DataONE-SerialVersion", dr.getSerialVersion().toString());
1124
1125 6502 leinfelder
1126 6264 leinfelder
    }
1127
1128
    /**
1129
     * get the logs based on passed params.  Available
1130
     * See http://mule1.dataone.org/ArchitectureDocs/mn_api_crud.html#MN_crud.getLogRecords
1131
     * for more info
1132 6273 leinfelder
     * @throws NotImplemented
1133
     * @throws InvalidRequest
1134
     * @throws NotAuthorized
1135
     * @throws ServiceFailure
1136
     * @throws InvalidToken
1137
     * @throws IOException
1138 9833 tao
     * @throws MarshallingException
1139 6264 leinfelder
     */
1140 9833 tao
    private void getLog() throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest, NotImplemented, IOException, MarshallingException
1141 6264 leinfelder
    {
1142 6273 leinfelder
1143
        Date fromDate = null;
1144
        Date toDate = null;
1145 8810 leinfelder
        String event = null;
1146 6273 leinfelder
        Integer start = null;
1147
        Integer count = null;
1148 7099 leinfelder
        String pidFilter = null;
1149 6273 leinfelder
1150 6264 leinfelder
        try {
1151 6273 leinfelder
        	String fromDateS = params.get("fromDate")[0];
1152
            logMetacat.debug("param fromDateS: " + fromDateS);
1153 6469 leinfelder
            fromDate = DateTimeMarshaller.deserializeDateToUTC(fromDateS);
1154 6273 leinfelder
        } catch (Exception e) {
1155
        	logMetacat.warn("Could not parse fromDate: " + e.getMessage());
1156 6264 leinfelder
        }
1157 6273 leinfelder
        try {
1158
        	String toDateS = params.get("toDate")[0];
1159
            logMetacat.debug("param toDateS: " + toDateS);
1160 6469 leinfelder
            toDate = DateTimeMarshaller.deserializeDateToUTC(toDateS);
1161 6273 leinfelder
        } catch (Exception e) {
1162
        	logMetacat.warn("Could not parse toDate: " + e.getMessage());
1163
		}
1164
        try {
1165 8810 leinfelder
        	event = params.get("event")[0];
1166 6273 leinfelder
        } catch (Exception e) {
1167
        	logMetacat.warn("Could not parse event: " + e.getMessage());
1168
		}
1169
        logMetacat.debug("fromDate: " + fromDate + " toDate: " + toDate);
1170
1171
        try {
1172
        	start =  Integer.parseInt(params.get("start")[0]);
1173
        } catch (Exception e) {
1174
			logMetacat.warn("Could not parse start: " + e.getMessage());
1175
		}
1176
        try {
1177
        	count =  Integer.parseInt(params.get("count")[0]);
1178
        } catch (Exception e) {
1179
			logMetacat.warn("Could not parse count: " + e.getMessage());
1180
		}
1181
1182 7099 leinfelder
        try {
1183 9370 leinfelder
            pidFilter = params.get("idFilter")[0];
1184 7099 leinfelder
        } catch (Exception e) {
1185
            logMetacat.warn("Could not parse pidFilter: " + e.getMessage());
1186
        }
1187
1188 6273 leinfelder
        logMetacat.debug("calling getLogRecords");
1189 7101 leinfelder
        Log log = MNodeService.getInstance(request).getLogRecords(session, fromDate, toDate, event, pidFilter, start, count);
1190 6273 leinfelder
1191
        OutputStream out = response.getOutputStream();
1192
        response.setStatus(200);
1193
        response.setContentType("text/xml");
1194
1195 6367 leinfelder
        TypeMarshaller.marshalTypeToOutputStream(log, out);
1196 6273 leinfelder
1197 6264 leinfelder
    }
1198
1199 7417 leinfelder
1200
1201 6264 leinfelder
    /**
1202
     * Implements REST version of DataONE CRUD API --> get
1203 6285 cjones
     * @param pid ID of data object to be read
1204 6273 leinfelder
     * @throws NotImplemented
1205
     * @throws InvalidRequest
1206
     * @throws NotFound
1207
     * @throws NotAuthorized
1208
     * @throws ServiceFailure
1209
     * @throws InvalidToken
1210
     * @throws IOException
1211 9833 tao
     * @throws MarshallingException
1212 6264 leinfelder
     */
1213 9833 tao
    protected void getObject(String pid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, InvalidRequest, NotImplemented, IOException, MarshallingException {
1214 6264 leinfelder
        OutputStream out = null;
1215 6273 leinfelder
1216 6285 cjones
        if (pid != null) { //get a specific document
1217 6273 leinfelder
            Identifier id = new Identifier();
1218 6285 cjones
            id.setValue(pid);
1219 6273 leinfelder
1220 6542 leinfelder
            SystemMetadata sm = MNodeService.getInstance(request).getSystemMetadata(session, id);
1221 6264 leinfelder
1222 7412 leinfelder
            // set the headers for the content
1223 9235 leinfelder
            String mimeType = null;
1224
            String charset = null;
1225 9244 leinfelder
            ObjectFormat objectFormat = null;
1226 9235 leinfelder
1227 9244 leinfelder
            try {
1228
            	objectFormat = ObjectFormatCache.getInstance().getFormat(sm.getFormatId());
1229
        	} catch (BaseException be) {
1230
        		logMetacat.warn("Could not lookup ObjectFormat for: " + sm.getFormatId(), be);
1231
        	}
1232 9235 leinfelder
            // do we have mediaType/encoding in SM?
1233
            MediaType mediaType = sm.getMediaType();
1234 9819 tao
            if (mediaType == null && objectFormat != null) {
1235 9235 leinfelder
            	try {
1236 9244 leinfelder
            		mediaType = objectFormat.getMediaType();
1237
            	} catch (Exception e) {
1238
            		logMetacat.warn("Could not lookup MediaType for: " + sm.getFormatId(), e);
1239 9235 leinfelder
            	}
1240
            }
1241
            if (mediaType != null) {
1242 9268 tao
                mimeType = mediaType.getName();
1243
                if (mediaType.getPropertyList() != null) {
1244
                	Iterator<MediaTypeProperty> iter = mediaType.getPropertyList().iterator();
1245 9235 leinfelder
                	while (iter.hasNext()) {
1246
                		MediaTypeProperty mtp = iter.next();
1247
                		if (mtp.getName().equalsIgnoreCase("charset")) {
1248
                			charset = mtp.getValue();
1249
                			mimeType += "; charset=" + charset;
1250
                			break;
1251
                		}
1252
                	}
1253
                }
1254
            }
1255
            // check object format
1256
1257
            // use the fallback from v1 impl
1258 7412 leinfelder
            if (mimeType == null) {
1259 9235 leinfelder
	            mimeType = ObjectFormatInfo.instance().getMimeType(sm.getFormatId().getValue());
1260
1261
	            // still null?
1262
	            if (mimeType == null) {
1263
	            	mimeType = "application/octet-stream";
1264
	            }
1265 6273 leinfelder
            }
1266 9235 leinfelder
1267
            // check for filename in SM first
1268
            String filename = sm.getFileName();
1269
            // then fallback to using id and extension
1270
            if (filename == null) {
1271 9244 leinfelder
	            String extension = objectFormat.getExtension();
1272
	            if (extension == null) {
1273
	            	extension = ObjectFormatInfo.instance().getExtension(sm.getFormatId().getValue());
1274
	            }
1275 9235 leinfelder
	            filename = id.getValue();
1276
	            if (extension != null) {
1277 9673 cjones
	            	filename = id.getValue() + "." + extension;
1278 9235 leinfelder
	            }
1279 7412 leinfelder
            }
1280
            response.setContentType(mimeType);
1281
            response.setHeader("Content-Disposition", "inline; filename=" + filename);
1282 6273 leinfelder
1283 6542 leinfelder
            InputStream data = MNodeService.getInstance(request).get(session, id);
1284 6273 leinfelder
1285
            out = response.getOutputStream();
1286
            IOUtils.copyLarge(data, out);
1287
1288
        }
1289
        else
1290
        { //call listObjects with specified params
1291
            Date startTime = null;
1292
            Date endTime = null;
1293 7100 leinfelder
            ObjectFormatIdentifier formatId = null;
1294 8810 leinfelder
            Identifier identifier = null;
1295 7462 leinfelder
            boolean replicaStatus = true;
1296 6273 leinfelder
            int start = 0;
1297
            //TODO: make the max count into a const
1298
            int count = 1000;
1299
            Enumeration paramlist = request.getParameterNames();
1300
            while (paramlist.hasMoreElements())
1301
            { //parse the params and make the crud call
1302
                String name = (String) paramlist.nextElement();
1303
                String[] value = (String[])request.getParameterValues(name);
1304
1305 6799 cjones
                if (name.equals("fromDate") && value != null)
1306 6264 leinfelder
                {
1307 6273 leinfelder
                    try
1308 6264 leinfelder
                    {
1309 6273 leinfelder
                      //startTime = dateFormat.parse(value[0]);
1310 6469 leinfelder
                    	startTime = DateTimeMarshaller.deserializeDateToUTC(value[0]);
1311
                        //startTime = parseDateAndConvertToGMT(value[0]);
1312 6264 leinfelder
                    }
1313 6273 leinfelder
                    catch(Exception e)
1314 6799 cjones
                    {  //if we can't parse it, just don't use the fromDate param
1315
                        logMetacat.warn("Could not parse fromDate: " + value[0]);
1316 6273 leinfelder
                        startTime = null;
1317 6264 leinfelder
                    }
1318 6273 leinfelder
                }
1319 6799 cjones
                else if(name.equals("toDate") && value != null)
1320 6273 leinfelder
                {
1321
                    try
1322 6264 leinfelder
                    {
1323 6469 leinfelder
                    	endTime = DateTimeMarshaller.deserializeDateToUTC(value[0]);
1324 6264 leinfelder
                    }
1325 6273 leinfelder
                    catch(Exception e)
1326 6799 cjones
                    {  //if we can't parse it, just don't use the toDate param
1327
                        logMetacat.warn("Could not parse toDate: " + value[0]);
1328 6273 leinfelder
                        endTime = null;
1329
                    }
1330 6264 leinfelder
                }
1331 7100 leinfelder
                else if(name.equals("formatId") && value != null)
1332 6264 leinfelder
                {
1333 7100 leinfelder
                	formatId = new ObjectFormatIdentifier();
1334
                	formatId.setValue(value[0]);
1335 6264 leinfelder
                }
1336 8810 leinfelder
                else if(name.equals("identifier") && value != null)
1337
                {
1338
                	identifier = new Identifier();
1339
                	identifier.setValue(value[0]);
1340
                }
1341 6273 leinfelder
                else if(name.equals("replicaStatus") && value != null)
1342 6264 leinfelder
                {
1343 6273 leinfelder
                    if(value != null &&
1344
                       value.length > 0 &&
1345 7462 leinfelder
                       (value[0].equalsIgnoreCase("false") || value[0].equalsIgnoreCase("no")))
1346 6273 leinfelder
                    {
1347 7462 leinfelder
                        replicaStatus = false;
1348 6273 leinfelder
                    }
1349 6264 leinfelder
                }
1350 6273 leinfelder
                else if(name.equals("start") && value != null)
1351 6264 leinfelder
                {
1352 6273 leinfelder
                    start = new Integer(value[0]).intValue();
1353 6264 leinfelder
                }
1354 6273 leinfelder
                else if(name.equals("count") && value != null)
1355 6264 leinfelder
                {
1356 6273 leinfelder
                    count = new Integer(value[0]).intValue();
1357 6264 leinfelder
                }
1358
            }
1359 6273 leinfelder
            //make the crud call
1360
            logMetacat.debug("session: " + session + " startTime: " + startTime +
1361 7100 leinfelder
                    " endTime: " + endTime + " formatId: " +
1362
                    formatId + " replicaStatus: " + replicaStatus +
1363 6273 leinfelder
                    " start: " + start + " count: " + count);
1364
1365
            ObjectList ol =
1366 6542 leinfelder
           	 MNodeService.getInstance(request).listObjects(session, startTime, endTime,
1367 8810 leinfelder
           			formatId, identifier, replicaStatus, start, count);
1368 6352 cjones
1369 6273 leinfelder
            out = response.getOutputStream();
1370
            response.setStatus(200);
1371
            response.setContentType("text/xml");
1372
            // Serialize and write it to the output stream
1373 6367 leinfelder
            TypeMarshaller.marshalTypeToOutputStream(ol, out);
1374 6273 leinfelder
1375 6264 leinfelder
        }
1376 6273 leinfelder
1377 6264 leinfelder
    }
1378
1379 6273 leinfelder
1380 6264 leinfelder
    /**
1381 7855 leinfelder
     * Retrieve data package as Bagit zip
1382
     * @param pid
1383
     * @throws NotImplemented
1384
     * @throws NotFound
1385
     * @throws NotAuthorized
1386
     * @throws ServiceFailure
1387
     * @throws InvalidToken
1388
     * @throws IOException
1389 8810 leinfelder
     * @throws InvalidRequest
1390 7855 leinfelder
     */
1391 8810 leinfelder
    protected void getPackage(String format, String pid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, IOException, InvalidRequest {
1392 7855 leinfelder
1393
        Identifier id = new Identifier();
1394
        id.setValue(pid);
1395 8810 leinfelder
        ObjectFormatIdentifier formatId = null;
1396
        if (format != null) {
1397
        	formatId = new ObjectFormatIdentifier();
1398
        	formatId.setValue(format);
1399
        }
1400
		InputStream is = MNodeService.getInstance(request).getPackage(session, formatId , id);
1401 7855 leinfelder
1402 8160 leinfelder
        // use the provided filename
1403
        String filename = null;
1404
        if (is instanceof DeleteOnCloseFileInputStream) {
1405
            filename = ((DeleteOnCloseFileInputStream)is).getFile().getName();
1406
        } else {
1407
        	filename = "dataPackage-" + System.currentTimeMillis() + ".zip";
1408
        }
1409 8034 leinfelder
        response.setHeader("Content-Disposition", "inline; filename=" + filename);
1410 7855 leinfelder
        response.setContentType("application/zip");
1411
        response.setStatus(200);
1412
        OutputStream out = response.getOutputStream();
1413
1414
        // write it to the output stream
1415
        IOUtils.copyLarge(is, out);
1416
   }
1417
1418 7864 leinfelder
	protected void publish(String pid) throws InvalidToken, ServiceFailure,
1419
			NotAuthorized, NotFound, NotImplemented, IOException,
1420 9833 tao
			MarshallingException, InvalidRequest, IdentifierNotUnique,
1421 7864 leinfelder
			UnsupportedType, InsufficientResources, InvalidSystemMetadata {
1422
1423
		// publish the object
1424
		Identifier originalIdentifier = new Identifier();
1425
		originalIdentifier.setValue(pid);
1426
		Identifier newIdentifier = MNodeService.getInstance(request).publish(session, originalIdentifier);
1427
1428
		response.setStatus(200);
1429
		response.setContentType("text/xml");
1430
		OutputStream out = response.getOutputStream();
1431
1432
		// write new identifier to the output stream
1433
		TypeMarshaller.marshalTypeToOutputStream(newIdentifier, out);
1434
	}
1435
1436 7855 leinfelder
    /**
1437 6273 leinfelder
     * Retrieve System Metadata
1438 6285 cjones
     * @param pid
1439 6273 leinfelder
     * @throws InvalidToken
1440
     * @throws ServiceFailure
1441
     * @throws NotAuthorized
1442
     * @throws NotFound
1443
     * @throws InvalidRequest
1444
     * @throws NotImplemented
1445
     * @throws IOException
1446 9833 tao
     * @throws MarshallingException
1447 6264 leinfelder
     */
1448 9833 tao
    protected void getSystemMetadataObject(String pid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, InvalidRequest, NotImplemented, IOException, MarshallingException {
1449 6273 leinfelder
1450
        Identifier id = new Identifier();
1451 6285 cjones
        id.setValue(pid);
1452 6542 leinfelder
        SystemMetadata sysmeta = MNodeService.getInstance(request).getSystemMetadata(session, id);
1453 6273 leinfelder
1454
        response.setContentType("text/xml");
1455
        response.setStatus(200);
1456
        OutputStream out = response.getOutputStream();
1457
1458
        // Serialize and write it to the output stream
1459 6367 leinfelder
        TypeMarshaller.marshalTypeToOutputStream(sysmeta, out);
1460 6273 leinfelder
   }
1461 6264 leinfelder
1462
1463
    /**
1464
     * Inserts or updates the object
1465
     *
1466 6285 cjones
     * @param pid - ID of data object to be inserted or updated.  If action is update, the pid
1467 6264 leinfelder
     *               is the existing pid.  If insert, the pid is the new one
1468 6269 leinfelder
     * @throws InvalidRequest
1469
     * @throws ServiceFailure
1470 9833 tao
     * @throws MarshallingException
1471 6269 leinfelder
     * @throws NotImplemented
1472
     * @throws InvalidSystemMetadata
1473
     * @throws InsufficientResources
1474
     * @throws UnsupportedType
1475
     * @throws IdentifierNotUnique
1476
     * @throws NotAuthorized
1477
     * @throws InvalidToken
1478
     * @throws NotFound
1479 6273 leinfelder
     * @throws IOException
1480 6367 leinfelder
     * @throws IllegalAccessException
1481
     * @throws InstantiationException
1482 6264 leinfelder
     */
1483 9833 tao
    protected void putObject(String trailingPid, String action) throws ServiceFailure, InvalidRequest, MarshallingException, InvalidToken, NotAuthorized, IdentifierNotUnique, UnsupportedType, InsufficientResources, InvalidSystemMetadata, NotImplemented, NotFound, IOException, InstantiationException, IllegalAccessException {
1484 6972 leinfelder
1485
    	// Read the incoming data from its Mime Multipart encoding
1486 6269 leinfelder
    	Map<String, File> files = collectMultipartFiles();
1487 6972 leinfelder
1488 6975 leinfelder
    	Identifier pid = new Identifier();
1489 6972 leinfelder
        if (trailingPid == null) {
1490 6975 leinfelder
	        // get the pid string from the body and set the value
1491
	        String pidString = multipartparams.get("pid").get(0);
1492 7051 cjones
	        if (pidString != null) {
1493
            pid.setValue(pidString);
1494
1495
          } else {
1496
              throw new InvalidRequest("1102", "The pid param must be included and contain the identifier.");
1497
1498
          }
1499 6972 leinfelder
        } else {
1500
        	// use the pid included in the URL
1501
        	pid.setValue(trailingPid);
1502
        }
1503
        logMetacat.debug("putObject with pid " + pid.getValue());
1504
        logMetacat.debug("Entering putObject: " + pid.getValue() + "/" + action);
1505
1506 6269 leinfelder
        InputStream object = null;
1507
        InputStream sysmeta = null;
1508
        File smFile = files.get("sysmeta");
1509
        sysmeta = new FileInputStream(smFile);
1510
        File objFile = files.get("object");
1511
        object = new FileInputStream(objFile);
1512
1513 6927 cjones
        // ensure we have the object bytes
1514
        if  ( objFile == null ) {
1515
            throw new InvalidRequest("1102", "The object param must contain the object bytes.");
1516
1517
        }
1518
1519
        // ensure we have the system metadata
1520
        if  ( smFile == null ) {
1521
            throw new InvalidRequest("1102", "The sysmeta param must contain the system metadata document.");
1522
1523
        }
1524
1525 6972 leinfelder
        response.setStatus(200);
1526
        response.setContentType("text/xml");
1527
        OutputStream out = response.getOutputStream();
1528
1529 6269 leinfelder
        if (action.equals(FUNCTION_NAME_INSERT)) {
1530
            // handle inserts
1531
            logMetacat.debug("Commence creation...");
1532 6367 leinfelder
            SystemMetadata smd = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysmeta);
1533 6264 leinfelder
1534 6972 leinfelder
            logMetacat.debug("creating object with pid " + pid.getValue());
1535
            Identifier rId = MNodeService.getInstance(request).create(session, pid, object, smd);
1536 6367 leinfelder
            TypeMarshaller.marshalTypeToOutputStream(rId, out);
1537 6264 leinfelder
1538 6269 leinfelder
        } else if (action.equals(FUNCTION_NAME_UPDATE)) {
1539
        	// handle updates
1540
1541
            // construct pids
1542 6972 leinfelder
            Identifier newPid = null;
1543 6269 leinfelder
            try {
1544
            	String newPidString = multipartparams.get("newPid").get(0);
1545 6975 leinfelder
            	newPid = new Identifier();
1546
            	newPid.setValue(newPidString);
1547 6269 leinfelder
            } catch (Exception e) {
1548 6972 leinfelder
				logMetacat.error("Could not get newPid from request");
1549 6269 leinfelder
			}
1550
            logMetacat.debug("Commence update...");
1551
1552
            // get the systemmetadata object
1553 6367 leinfelder
            SystemMetadata smd = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysmeta);
1554 6264 leinfelder
1555 6972 leinfelder
            Identifier rId = MNodeService.getInstance(request).update(session, pid, object, newPid, smd);
1556 6367 leinfelder
            TypeMarshaller.marshalTypeToOutputStream(rId, out);
1557 6269 leinfelder
        } else {
1558
            throw new InvalidRequest("1000", "Operation must be create or update.");
1559
        }
1560 6972 leinfelder
1561 6264 leinfelder
    }
1562
1563
    /**
1564
     * Handle delete
1565 6285 cjones
     * @param pid ID of data object to be deleted
1566 6264 leinfelder
     * @throws IOException
1567 6273 leinfelder
     * @throws InvalidRequest
1568
     * @throws NotImplemented
1569
     * @throws NotFound
1570
     * @throws NotAuthorized
1571
     * @throws ServiceFailure
1572
     * @throws InvalidToken
1573 9833 tao
     * @throws MarshallingException
1574 6264 leinfelder
     */
1575 9833 tao
    private void deleteObject(String pid) throws IOException, InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, InvalidRequest, MarshallingException
1576 6264 leinfelder
    {
1577
1578
        OutputStream out = response.getOutputStream();
1579
        response.setStatus(200);
1580
        response.setContentType("text/xml");
1581
1582
        Identifier id = new Identifier();
1583 6285 cjones
        id.setValue(pid);
1584 6273 leinfelder
1585
        logMetacat.debug("Calling delete");
1586 6542 leinfelder
        MNodeService.getInstance(request).delete(session, id);
1587 6367 leinfelder
        TypeMarshaller.marshalTypeToOutputStream(id, out);
1588 6273 leinfelder
1589 7153 leinfelder
    }
1590
1591
    /**
1592
     * Archives the given pid
1593
     * @param pid
1594
     * @throws InvalidToken
1595
     * @throws ServiceFailure
1596
     * @throws NotAuthorized
1597
     * @throws NotFound
1598
     * @throws NotImplemented
1599
     * @throws IOException
1600 9833 tao
     * @throws MarshallingException
1601 7153 leinfelder
     */
1602 9833 tao
    private void archive(String pid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, IOException, MarshallingException {
1603 6264 leinfelder
1604 7153 leinfelder
        OutputStream out = response.getOutputStream();
1605
        response.setStatus(200);
1606
        response.setContentType("text/xml");
1607
1608
        Identifier id = new Identifier();
1609
        id.setValue(pid);
1610
1611 7154 leinfelder
        logMetacat.debug("Calling archive");
1612 7153 leinfelder
        MNodeService.getInstance(request).archive(session, id);
1613
1614
        TypeMarshaller.marshalTypeToOutputStream(id, out);
1615
1616
    }
1617
1618 9833 tao
	protected SynchronizationFailed collectSynchronizationFailed() throws IOException, ServiceFailure, InvalidRequest, MarshallingException, InstantiationException, IllegalAccessException, ParserConfigurationException, SAXException  {
1619 6514 leinfelder
1620
		// Read the incoming data from its Mime Multipart encoding
1621
		logMetacat.debug("Disassembling MIME multipart form");
1622
		InputStream sf = null;
1623
1624
		// handle MMP inputs
1625
		File tmpDir = getTempDirectory();
1626
		logMetacat.debug("temp dir: " + tmpDir.getAbsolutePath());
1627
		MultipartRequestResolver mrr =
1628 9099 jones
			new MultipartRequestResolver(tmpDir.getAbsolutePath(), MAX_UPLOAD_SIZE, 0);
1629 6514 leinfelder
		MultipartRequest mr = null;
1630
		try {
1631
			mr = mrr.resolveMultipart(request);
1632
		} catch (Exception e) {
1633
			throw new ServiceFailure("2161",
1634
					"Could not resolve multipart: " + e.getMessage());
1635
		}
1636
		logMetacat.debug("resolved multipart request");
1637
		Map<String, File> files = mr.getMultipartFiles();
1638
		if (files == null || files.keySet() == null) {
1639
			throw new InvalidRequest("2163",
1640
					"must have multipart file with name 'message'");
1641
		}
1642
		logMetacat.debug("got multipart files");
1643
1644
		multipartparams = mr.getMultipartParameters();
1645
1646
		File sfFile = files.get("message");
1647
		if (sfFile == null) {
1648
			throw new InvalidRequest("2163",
1649
					"Missing the required file-part 'message' from the multipart request.");
1650
		}
1651
		logMetacat.debug("sfFile: " + sfFile.getAbsolutePath());
1652
		sf = new FileInputStream(sfFile);
1653
1654
		SynchronizationFailed syncFailed = (SynchronizationFailed) ExceptionHandler.deserializeXml(sf, "Error deserializing exception");
1655
		return syncFailed;
1656
	}
1657 9122 tao
1658
	/**
1659
	 * Update the system metadata for a specified identifier
1660
	 * @throws ServiceFailure
1661
	 * @throws InvalidRequest
1662
	 * @throws InstantiationException
1663
	 * @throws IllegalAccessException
1664
	 * @throws IOException
1665 9833 tao
	 * @throws MarshallingException
1666 9122 tao
	 * @throws NotImplemented
1667
	 * @throws NotAuthorized
1668
	 * @throws InvalidSystemMetadata
1669
	 * @throws InvalidToken
1670
	 */
1671
	protected void updateSystemMetadata() throws ServiceFailure, InvalidRequest,
1672 9833 tao
	                        InstantiationException, IllegalAccessException, IOException, MarshallingException, NotImplemented,
1673 9122 tao
	                        NotAuthorized, InvalidSystemMetadata, InvalidToken {
1674
	    // Read the incoming data from its Mime Multipart encoding
1675
        Map<String, File> files = collectMultipartFiles();
1676
1677
        // get the encoded pid string from the body and make the object
1678
        String pidString = multipartparams.get("pid").get(0);
1679
        Identifier pid = new Identifier();
1680
        pid.setValue(pidString);
1681
1682
        logMetacat.debug("updateSystemMetadata: " + pid);
1683 6514 leinfelder
1684 9122 tao
        // get the system metadata from the request
1685
        File smFile = files.get("sysmeta");
1686
        FileInputStream sysmeta = new FileInputStream(smFile);
1687
        SystemMetadata systemMetadata = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysmeta);
1688
1689
        logMetacat.debug("updating system metadata with pid " + pid.getValue());
1690
1691
        MNodeService.getInstance(request).updateSystemMetadata(session, pid, systemMetadata);
1692
	}
1693
1694 6264 leinfelder
}