Project

General

Profile

1 5211 jones
/**
2
 *  '$RCSfile$'
3 5805 berkley
 *  Copyright: 2011 Regents of the University of California and the
4 5211 jones
 *              National Center for Ecological Analysis and Synthesis
5
 *
6
 *   '$Author: Serhan AKIN $'
7
 *     '$Date: 2009-06-13 15:28:13 +0300  $'
8
 *
9
 * This program is free software; you can redistribute it and/or modify
10
 * it under the terms of the GNU General Public License as published by
11
 * the Free Software Foundation; either version 2 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program; if not, write to the Free Software
21
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
 */
23
package edu.ucsb.nceas.metacat.restservice;
24
25 6130 leinfelder
import java.io.File;
26 6269 leinfelder
import java.io.FileInputStream;
27 6590 cjones
import java.io.FileNotFoundException;
28 6130 leinfelder
import java.io.IOException;
29
import java.io.InputStream;
30
import java.io.OutputStream;
31
import java.io.PrintWriter;
32 7737 leinfelder
import java.security.PrivateKey;
33
import java.security.cert.X509Certificate;
34 6130 leinfelder
import java.util.Enumeration;
35
import java.util.Hashtable;
36 6269 leinfelder
import java.util.Iterator;
37
import java.util.List;
38
import java.util.Map;
39 6130 leinfelder
import java.util.Timer;
40 5211 jones
41
import javax.servlet.ServletContext;
42
import javax.servlet.http.HttpServletRequest;
43
import javax.servlet.http.HttpServletResponse;
44 6514 leinfelder
import javax.xml.parsers.ParserConfigurationException;
45 6067 rnahf
46 6269 leinfelder
import org.apache.commons.fileupload.FileUploadException;
47 5299 jones
import org.apache.commons.io.IOUtils;
48 5211 jones
import org.apache.log4j.Logger;
49 6244 leinfelder
import org.dataone.client.auth.CertificateManager;
50 6269 leinfelder
import org.dataone.mimemultipart.MultipartRequest;
51
import org.dataone.mimemultipart.MultipartRequestResolver;
52 7737 leinfelder
import org.dataone.portal.PortalCertificateManager;
53 5299 jones
import org.dataone.service.exceptions.BaseException;
54 6269 leinfelder
import org.dataone.service.exceptions.InvalidRequest;
55
import org.dataone.service.exceptions.ServiceFailure;
56 6514 leinfelder
import org.dataone.service.types.v1.AccessPolicy;
57 7773 leinfelder
import org.dataone.service.types.v1.Group;
58
import org.dataone.service.types.v1.Person;
59 6590 cjones
import org.dataone.service.types.v1.Replica;
60
import org.dataone.service.types.v1.ReplicationPolicy;
61 6366 leinfelder
import org.dataone.service.types.v1.Session;
62 7773 leinfelder
import org.dataone.service.types.v1.Subject;
63
import org.dataone.service.types.v1.SubjectInfo;
64 6366 leinfelder
import org.dataone.service.types.v1.SystemMetadata;
65 6860 cjones
import org.dataone.service.util.ExceptionHandler;
66 6367 leinfelder
import org.dataone.service.util.TypeMarshaller;
67 5320 jones
import org.jibx.runtime.JiBXException;
68 6514 leinfelder
import org.xml.sax.SAXException;
69 5211 jones
70
import edu.ucsb.nceas.metacat.MetacatHandler;
71 5637 berkley
import edu.ucsb.nceas.metacat.properties.PropertyService;
72 7778 leinfelder
import edu.ucsb.nceas.metacat.service.SessionService;
73 7773 leinfelder
import edu.ucsb.nceas.metacat.util.RequestUtil;
74
import edu.ucsb.nceas.metacat.util.SessionData;
75 5637 berkley
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
76 5211 jones
/**
77
 *
78 6268 leinfelder
 * Base class for handling D1 REST calls in Metacat
79 5211 jones
 *
80 6268 leinfelder
 * @author leinfelder
81 5211 jones
 */
82 6267 leinfelder
public class D1ResourceHandler {
83 5211 jones
84
    /**HTTP Verb GET*/
85
    public static final byte GET = 1;
86
    /**HTTP Verb POST*/
87
    public static final byte POST = 2;
88
    /**HTTP Verb PUT*/
89
    public static final byte PUT = 3;
90
    /**HTTP Verb DELETE*/
91
    public static final byte DELETE = 4;
92 5651 berkley
    /**HTTP Verb HEAD*/
93
    public static final byte HEAD = 5;
94 5211 jones
95
    /*
96
     * API Resources
97
     */
98 6271 leinfelder
    protected static final String RESOURCE_BASE_URL = "d1";
99
100 6247 leinfelder
    protected static final String RESOURCE_OBJECTS = "object";
101
    protected static final String RESOURCE_META = "meta";
102
    protected static final String RESOURCE_LOG = "log";
103 6249 leinfelder
104 7417 leinfelder
    protected static final String RESOURCE_QUERY = "query";
105
106 6249 leinfelder
    protected static final String RESOURCE_IS_AUTHORIZED = "isAuthorized";
107
    protected static final String RESOURCE_ACCESS_RULES = "accessRules";
108 5211 jones
109 6590 cjones
110 5211 jones
    /*
111
     * API Functions used as URL parameters
112
     */
113 6247 leinfelder
    protected static final String FUNCTION_NAME_INSERT = "insert";
114
    protected static final String FUNCTION_NAME_UPDATE = "update";
115 5414 berkley
116 6247 leinfelder
    protected ServletContext servletContext;
117
    protected Logger logMetacat;
118
    protected MetacatHandler handler;
119
    protected HttpServletRequest request;
120
    protected HttpServletResponse response;
121 5211 jones
122 6247 leinfelder
    protected Hashtable<String, String[]> params;
123 6269 leinfelder
    protected Map<String, List<String>> multipartparams;
124 6244 leinfelder
125
    // D1 certificate-based authentication
126 6247 leinfelder
    protected Session session;
127 5211 jones
128
    /**Initializes new instance by setting servlet context,request and response*/
129 6267 leinfelder
    public D1ResourceHandler(ServletContext servletContext,
130 5211 jones
            HttpServletRequest request, HttpServletResponse response) {
131
        this.servletContext = servletContext;
132
        this.request = request;
133
        this.response = response;
134
    }
135
136
    /**
137 6268 leinfelder
     * This function is called from REST API servlet and handles each request
138 5211 jones
     *
139
     * @param httpVerb (GET, POST, PUT or DELETE)
140
     */
141
    public void handle(byte httpVerb) {
142 6267 leinfelder
        logMetacat = Logger.getLogger(D1ResourceHandler.class);
143 5211 jones
        try {
144 6268 leinfelder
145 7773 leinfelder
        	// initialize the session - three options
146
        	// #1
147
        	// load session from certificate in request
148 6244 leinfelder
            session = CertificateManager.getInstance().getSession(request);
149 7773 leinfelder
150
            // #2
151
            if (session == null) {
152
	        	// check for session-based certificate from the portal
153 7778 leinfelder
            	try {
154
		        	String configurationFileName = servletContext.getInitParameter("oa4mp:client.config.file");
155
		        	String configurationFilePath = servletContext.getRealPath(configurationFileName);
156
		        	PortalCertificateManager portalManager = new PortalCertificateManager(configurationFilePath);
157
		        	logMetacat.debug("Initialized the PortalCertificateManager using config file: " + configurationFilePath);
158
		        	X509Certificate certificate = portalManager.getCertificate(request);
159
		        	logMetacat.debug("Retrieved certificate: " + certificate);
160
			    	PrivateKey key = portalManager.getPrivateKey(request);
161
			    	logMetacat.debug("Retrieved key: " + key);
162
			    	if (certificate != null && key != null) {
163
			        	request.setAttribute("javax.servlet.request.X509Certificate", certificate);
164
			        	logMetacat.debug("Added certificate to the request: " + certificate.toString());
165
			    	}
166
167
		            // reload session from certificate that we jsut set in request
168
		            session = CertificateManager.getInstance().getSession(request);
169
            	} catch (Throwable t) {
170
            		// don't require configured OAuth4MyProxy
171
            		logMetacat.error(t.getMessage(), t);
172
            	}
173 7773 leinfelder
            }
174
175
            // #3
176
            // last resort, check for Metacat sessionid
177
            if (session == null) {
178
	            SessionData sessionData = RequestUtil.getSessionData(request);
179
				if (sessionData != null) {
180 7778 leinfelder
					// is it not the public session?
181
					if (!SessionService.getInstance().getPublicSession().getUserName().equals(sessionData.getUserName())) {
182
						session = new Session();
183
						String userName = sessionData.getUserName();
184
						String[] groupNames = sessionData.getGroupNames();
185
						Subject userSubject = new Subject();
186
						userSubject.setValue(userName);
187
						session.setSubject(userSubject);
188
						SubjectInfo subjectInfo = new SubjectInfo();
189
						Person person = new Person();
190
						person.setSubject(userSubject);
191
						if (groupNames != null && groupNames.length > 0) {
192
							for (String groupName: groupNames) {
193
								Group group = new Group();
194
								group.setGroupName(groupName);
195
								Subject groupSubject = new Subject();
196
								groupSubject.setValue(groupName);
197
								group.setSubject(groupSubject);
198
								subjectInfo.addGroup(group);
199
								person.addIsMemberOf(groupSubject);
200
							}
201 7773 leinfelder
						}
202 7778 leinfelder
						subjectInfo.addPerson(person);
203
						session.setSubjectInfo(subjectInfo);
204 7773 leinfelder
					}
205
				}
206
            }
207
208 6268 leinfelder
            // initialize the parameters
209
            params = new Hashtable<String, String[]>();
210
            initParams();
211 5211 jones
212 6268 leinfelder
            // create the handler for interacting with Metacat
213
            Timer timer = new Timer();
214
            handler = new MetacatHandler(timer);
215 5211 jones
216
        } catch (Exception e) {
217 6268 leinfelder
        	// TODO: more D1 structure when failing here
218
        	response.setStatus(400);
219
            printError("Incorrect resource!", response);
220
            logMetacat.error(e.getClass() + ": " + e.getMessage(), e);
221 5211 jones
        }
222
    }
223 6994 leinfelder
224
    /**
225
     * subclasses should provide a more useful implementation
226
     * @return
227
     */
228
    protected boolean isD1Enabled() {
229
230
    	return true;
231
    }
232 5374 berkley
233 6514 leinfelder
    protected String parseTrailing(String resource, String token) {
234
    	// get the rest
235
        String extra = null;
236
        if (resource.indexOf(token) != -1) {
237
        	// what comes after the token?
238
            extra = resource.substring(resource.indexOf(token) + token.length());
239
            // remove the slash
240
            if (extra.startsWith("/")) {
241
            	extra = extra.substring(1);
242
            }
243
            // is there anything left?
244
            if (extra.length() == 0) {
245
            	extra = null;
246
            }
247
        }
248
        return extra;
249
    }
250 6590 cjones
251
    /**
252 6793 cjones
     * Parse the BaseException information for replication status failures if any
253
     *
254
     * @return failure  the BaseException failure, one of it's subclasses, or null
255
     * @throws ServiceFailure
256
     * @throws InvalidRequest
257
     * @throws JiBXException
258
     * @throws IllegalAccessException
259
     * @throws InstantiationException
260
     * @throws IOException
261
     */
262
    protected BaseException collectReplicationStatus()
263
        throws ServiceFailure, InvalidRequest, IOException,
264
        InstantiationException, IllegalAccessException, JiBXException {
265
266
        BaseException failure = null;
267
        File tmpDir = getTempDirectory();
268
        MultipartRequest mr = null;
269
        Map<String, File> mmFileParts = null;
270
        File exceptionFile = null;
271
        InputStream exceptionFileStream = null;
272
273
        // Read the incoming data from its Mime Multipart encoding
274
        logMetacat.debug("Parsing BaseException from the mime multipart entity");
275
276
        // handle MMP inputs
277
        MultipartRequestResolver mrr =
278
            new MultipartRequestResolver(tmpDir.getAbsolutePath(),1000000000, 0);
279
280
        try {
281
            mr = mrr.resolveMultipart(request);
282
            logMetacat.debug("Resolved the replication status BaseException multipart request.");
283
284
        } catch (IOException e) {
285
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
286
                e.getMessage());
287
288
        } catch (FileUploadException e) {
289
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
290
                e.getMessage());
291
292
        } catch (Exception e) {
293
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
294
                e.getMessage());
295
296
        }
297
298
        // get the map of file parts
299
        mmFileParts = mr.getMultipartFiles();
300
301
        if ( mmFileParts == null || mmFileParts.keySet() == null) {
302
            logMetacat.debug("BaseException for setReplicationStatus is null");
303
        }
304
305
        multipartparams = mr.getMultipartParameters();
306
        exceptionFile = mmFileParts.get("failure");
307
308 7065 leinfelder
        if ( exceptionFile != null && exceptionFile.length() > 0 ) {
309 6793 cjones
310 6860 cjones
            // deserialize the BaseException subclass
311 6793 cjones
            exceptionFileStream = new FileInputStream(exceptionFile);
312 6860 cjones
            try {
313
                failure = ExceptionHandler.deserializeXml(exceptionFileStream,
314
                    "Replication failed for an unknown reason.");
315 6793 cjones
316 6860 cjones
            } catch (ParserConfigurationException e) {
317
                throw new ServiceFailure("4700", "Couldn't parse the replication failure exception: " +
318
                        e.getMessage());
319
320
            } catch (SAXException e) {
321
                throw new ServiceFailure("4700", "Couldn't traverse the replication failure exception: " +
322
                        e.getMessage());
323
324
            }
325
326 6793 cjones
        }
327
328
329
        return failure;
330
331
    }
332 7092 cjones
333
    /**
334
     * Parse string parameters from the mime multipart entity of the request.
335
     * Populates the multipartparams map
336
     *
337
     * @throws IOException
338
     * @throws FileUploadException
339
     * @throws Exception
340
     */
341
    protected void collectMultipartParams()
342
        throws IOException, FileUploadException, Exception {
343
344
        File tmpDir = getTempDirectory();
345
        MultipartRequest mr = null;
346
347
        // Read the incoming data from its Mime Multipart encoding
348
        logMetacat.debug("Parsing rights holder info from the mime multipart entity");
349
350
        // handle MMP inputs
351
        MultipartRequestResolver mrr =
352
            new MultipartRequestResolver(tmpDir.getAbsolutePath(),1000000000, 0);
353
354
        mr = mrr.resolveMultipart(request);
355
        logMetacat.debug("Resolved the rights holder info from the mime multipart entity.");
356
357
        // we only have params in this MMP entity
358
        multipartparams = mr.getMultipartParameters();
359
360
    }
361 6793 cjones
362 7092 cjones
363 6793 cjones
    /**
364 6590 cjones
     * Parse the replication policy document out of the mime-multipart form data
365
     *
366
     * @return policy  the encoded policy
367
     * @throws ServiceFailure
368
     * @throws InvalidRequest
369
     * @throws IOException
370
     * @throws InstantiationException
371
     * @throws IllegalAccessException
372
     * @throws JiBXException
373
     */
374
    protected ReplicationPolicy collectReplicationPolicy()
375
        throws ServiceFailure, InvalidRequest, IOException, InstantiationException,
376
        IllegalAccessException, JiBXException {
377
378
        ReplicationPolicy policy = null;
379
        File tmpDir = getTempDirectory();
380
        MultipartRequest mr = null;
381
        Map<String, File> mmFileParts = null;
382
        File replPolicyFile = null;
383
        InputStream replPolicyStream = null;
384
385
        // Read the incoming data from its Mime Multipart encoding
386
        logMetacat.debug("Parsing ReplicationPolicy from the mime multipart entity");
387
388
        // handle MMP inputs
389
        MultipartRequestResolver mrr =
390
            new MultipartRequestResolver(tmpDir.getAbsolutePath(),1000000000, 0);
391
392
        try {
393
            mr = mrr.resolveMultipart(request);
394
            logMetacat.debug("Resolved the ReplicationPolicy multipart request.");
395
396
        } catch (IOException e) {
397
            throw new ServiceFailure("4882", "Couldn't resolve the multipart request: " +
398
                e.getMessage());
399
400
        } catch (FileUploadException e) {
401
            throw new ServiceFailure("4882", "Couldn't resolve the multipart request: " +
402 6793 cjones
                e.getMessage());
403 6590 cjones
404
        } catch (Exception e) {
405
            throw new ServiceFailure("4882", "Couldn't resolve the multipart request: " +
406 6793 cjones
                e.getMessage());
407 6590 cjones
408
        }
409
410
        // get the map of file parts
411
        mmFileParts = mr.getMultipartFiles();
412
413
        if ( mmFileParts == null || mmFileParts.keySet() == null) {
414
            throw new InvalidRequest("4883", "The multipart request must include " +
415
                "a file with the name 'policy'.");
416
417
        }
418
419
        multipartparams = mr.getMultipartParameters();
420
        replPolicyFile = mmFileParts.get("policy");
421
422
        if ( replPolicyFile == null ) {
423
            throw new InvalidRequest("4883", "The multipart request must include " +
424
            "a file with the name 'policy'.");
425
426
        }
427
428
429
        // deserialize the ReplicationPolicy
430
        replPolicyStream = new FileInputStream(replPolicyFile);
431
        policy = TypeMarshaller.unmarshalTypeFromStream(ReplicationPolicy.class, replPolicyStream);
432
433
        return policy;
434
435
    }
436
437
    /**
438
     * Parse the replica metadata document out of the mime-multipart form data
439
     *
440
     * @return replica  the encoded replica
441
     * @throws ServiceFailure
442
     * @throws InvalidRequest
443
     * @throws IOException
444
     * @throws InstantiationException
445
     * @throws IllegalAccessException
446
     * @throws JiBXException
447
     */
448
    protected Replica collectReplicaMetadata()
449
        throws ServiceFailure, InvalidRequest {
450
451
        Replica replica = null;
452
        File tmpDir = getTempDirectory();
453
        MultipartRequest mr = null;
454
        Map<String, File> mmFileParts = null;
455
        File replicaFile = null;
456
        InputStream replicaStream = null;
457
458
        // Read the incoming data from its Mime Multipart encoding
459
        logMetacat.debug("Parsing Replica from the mime multipart entity");
460
461
        // handle MMP inputs
462
        MultipartRequestResolver mrr =
463
            new MultipartRequestResolver(tmpDir.getAbsolutePath(),1000000000, 0);
464
465
        try {
466
            mr = mrr.resolveMultipart(request);
467
            logMetacat.debug("Resolved the Replica multipart request.");
468
469
        } catch (IOException e) {
470
            throw new ServiceFailure("4852", "Couldn't resolve the multipart request: " +
471
                e.getMessage());
472
473
        } catch (FileUploadException e) {
474
            throw new ServiceFailure("4852", "Couldn't resolve the multipart request: " +
475
                    e.getMessage());
476
477
        } catch (Exception e) {
478
            throw new ServiceFailure("4852", "Couldn't resolve the multipart request: " +
479
                    e.getMessage());
480
481
        }
482
483
        // get the map of file parts
484
        mmFileParts = mr.getMultipartFiles();
485
486
        if ( mmFileParts == null || mmFileParts.keySet() == null) {
487
            throw new InvalidRequest("4853", "The multipart request must include " +
488
                "a file with the name 'replicaMetadata'.");
489
490
        }
491
492
        multipartparams = mr.getMultipartParameters();
493
        replicaFile = mmFileParts.get("replicaMetadata");
494
495
        if ( replicaFile == null ) {
496
            throw new InvalidRequest("4853", "The multipart request must include " +
497
            "a file with the name 'replicaMetadata'.");
498
499
        }
500
501
502
        // deserialize the ReplicationPolicy
503
        try {
504
            replicaStream = new FileInputStream(replicaFile);
505
        } catch (FileNotFoundException e) {
506
            throw new ServiceFailure("4852", "Couldn't find the multipart file: " +
507
                    e.getMessage());
508
509
        }
510
511
        try {
512
            replica = TypeMarshaller.unmarshalTypeFromStream(Replica.class, replicaStream);
513
        } catch (IOException e) {
514
            throw new ServiceFailure("4852", "Couldn't deserialize the replica document: " +
515
                    e.getMessage());
516
517
        } catch (InstantiationException e) {
518
            throw new ServiceFailure("4852", "Couldn't deserialize the replica document: " +
519
                    e.getMessage());
520
521
        } catch (IllegalAccessException e) {
522
            throw new ServiceFailure("4852", "Couldn't deserialize the replica document: " +
523
                    e.getMessage());
524
525
        } catch (JiBXException e) {
526
            throw new ServiceFailure("4852", "Couldn't deserialize the replica document: " +
527
                    e.getMessage());
528
529
        }
530
531
        return replica;
532
533
    }
534 6514 leinfelder
535 6590 cjones
    protected AccessPolicy collectAccessPolicy()
536
        throws IOException, ServiceFailure, InvalidRequest, JiBXException,
537
        InstantiationException, IllegalAccessException, ParserConfigurationException,
538
        SAXException  {
539 6514 leinfelder
540
		// Read the incoming data from its Mime Multipart encoding
541
		logMetacat.debug("Disassembling MIME multipart form");
542
		InputStream ap = null;
543
544
		// handle MMP inputs
545
		File tmpDir = getTempDirectory();
546
		logMetacat.debug("temp dir: " + tmpDir.getAbsolutePath());
547
		MultipartRequestResolver mrr =
548
			new MultipartRequestResolver(tmpDir.getAbsolutePath(), 1000000000, 0);
549
		MultipartRequest mr = null;
550
		try {
551
			mr = mrr.resolveMultipart(request);
552
		} catch (Exception e) {
553
			throw new ServiceFailure("2161",
554
					"Could not resolve multipart: " + e.getMessage());
555
		}
556
		logMetacat.debug("resolved multipart request");
557
		Map<String, File> files = mr.getMultipartFiles();
558
		if (files == null || files.keySet() == null) {
559
			throw new InvalidRequest("2163",
560
					"must have multipart file with name 'accessPolicy'");
561
		}
562
		logMetacat.debug("got multipart files");
563
564
		multipartparams = mr.getMultipartParameters();
565
566
		File apFile = files.get("accessPolicy");
567
		if (apFile == null) {
568
			throw new InvalidRequest("2163",
569
					"Missing the required file-part 'accessPolicy' from the multipart request.");
570
		}
571
		logMetacat.debug("apFile: " + apFile.getAbsolutePath());
572
		ap = new FileInputStream(apFile);
573
574
		AccessPolicy accessPolicy = TypeMarshaller.unmarshalTypeFromStream(AccessPolicy.class, ap);
575
		return accessPolicy;
576
	}
577
578 6590 cjones
    protected SystemMetadata collectSystemMetadata()
579
        throws IOException, FileUploadException, ServiceFailure, InvalidRequest,
580
        JiBXException, InstantiationException, IllegalAccessException  {
581 6269 leinfelder
582
		// Read the incoming data from its Mime Multipart encoding
583
		logMetacat.debug("Disassembling MIME multipart form");
584
		InputStream sysmeta = null;
585
586
		// handle MMP inputs
587
		File tmpDir = getTempDirectory();
588
		logMetacat.debug("temp dir: " + tmpDir.getAbsolutePath());
589
		MultipartRequestResolver mrr =
590
			new MultipartRequestResolver(tmpDir.getAbsolutePath(), 1000000000, 0);
591
		MultipartRequest mr = null;
592
		try {
593
			mr = mrr.resolveMultipart(request);
594 7266 cjones
595 6269 leinfelder
		} catch (Exception e) {
596 7266 cjones
		  if ( logMetacat.isDebugEnabled() ) {
597
		      e.printStackTrace();
598
599
		  }
600 6269 leinfelder
			throw new ServiceFailure("1202",
601
					"Could not resolve multipart: " + e.getMessage());
602 7266 cjones
603 6269 leinfelder
		}
604
		logMetacat.debug("resolved multipart request");
605
		Map<String, File> files = mr.getMultipartFiles();
606
		if (files == null) {
607
			throw new ServiceFailure("1202",
608
					"register meta must have multipart file with name 'sysmeta'");
609
		}
610
		logMetacat.debug("got multipart files");
611
612
		if (files.keySet() == null) {
613
			logMetacat.error("No file keys in MMP request.");
614
			throw new ServiceFailure(
615
					"1202",
616
					"No file keys found in MMP.  "
617
							+ "register meta must have multipart file with name 'sysmeta'");
618
		}
619
620
		// for logging purposes, dump out the key-value pairs that
621
		// constitute the request
622
		// 3 types exist: request params, multipart params, and
623
		// multipart files
624
		Iterator it = files.keySet().iterator();
625
		logMetacat.debug("iterating through request parts: " + it);
626
		while (it.hasNext()) {
627
			String key = (String) it.next();
628
			logMetacat.debug("files key: " + key);
629
			logMetacat.debug("files value: " + files.get(key));
630
		}
631
632
		multipartparams = mr.getMultipartParameters();
633
		it = multipartparams.keySet().iterator();
634
		while (it.hasNext()) {
635
			String key = (String) it.next();
636
			logMetacat.debug("multipartparams key: " + key);
637
			logMetacat.debug("multipartparams value: " + multipartparams.get(key));
638
		}
639
640
		it = params.keySet().iterator();
641
		while (it.hasNext()) {
642
			String key = (String) it.next();
643
			logMetacat.debug("param key: " + key);
644
			logMetacat.debug("param value: " + params.get(key));
645
		}
646
		logMetacat.debug("done iterating the request...");
647
648
		File smFile = files.get("sysmeta");
649
		if (smFile == null) {
650
			throw new InvalidRequest("1102",
651
					"Missing the required file-part 'sysmeta' from the multipart request.");
652
		}
653
		logMetacat.debug("smFile: " + smFile.getAbsolutePath());
654
		sysmeta = new FileInputStream(smFile);
655
656
		logMetacat.debug("Commence creation...");
657 6367 leinfelder
		SystemMetadata systemMetadata = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysmeta);
658 6269 leinfelder
		return systemMetadata;
659
	}
660
661 6972 leinfelder
    /**
662
     * Process the MMP request that includes files for each param
663 7092 cjones
     * @return map of param key and the temp file that contains the encoded information
664 6972 leinfelder
     * @throws ServiceFailure
665
     * @throws InvalidRequest
666
     */
667 6590 cjones
    protected Map<String, File> collectMultipartFiles()
668
        throws ServiceFailure, InvalidRequest {
669 6269 leinfelder
670
        // Read the incoming data from its Mime Multipart encoding
671
        logMetacat.debug("Disassembling MIME multipart form");
672
673
        // handle MMP inputs
674
        File tmpDir = getTempDirectory();
675 6272 leinfelder
        logMetacat.debug("temp dir: " + tmpDir.getAbsolutePath());
676 6269 leinfelder
        MultipartRequestResolver mrr =
677
        	new MultipartRequestResolver(tmpDir.getAbsolutePath(), 1000000000, 0);
678
        MultipartRequest mr = null;
679 7092 cjones
		    try {
680
		    	  mr = mrr.resolveMultipart(request);
681
682
		    } catch (Exception e) {
683
                throw new ServiceFailure("1202",
684
                		"Could not resolve multipart files: " + e.getMessage());
685
		    }
686 6272 leinfelder
        logMetacat.debug("resolved multipart request");
687 6269 leinfelder
        Map<String, File> files = mr.getMultipartFiles();
688
        if (files == null) {
689 6972 leinfelder
            throw new ServiceFailure("1202", "no multipart files found");
690 6269 leinfelder
        }
691 6272 leinfelder
        logMetacat.debug("got multipart files");
692 6269 leinfelder
693
        if (files.keySet() == null) {
694 6272 leinfelder
            logMetacat.error("No file keys in MMP request.");
695 6972 leinfelder
            throw new ServiceFailure("1202", "No file keys found in MMP.");
696 6269 leinfelder
        }
697 6995 leinfelder
698
        multipartparams = mr.getMultipartParameters();
699 6269 leinfelder
700 7092 cjones
		    // for logging purposes, dump out the key-value pairs that constitute the request
701
		    // 3 types exist: request params, multipart params, and multipart files
702 6972 leinfelder
        if (logMetacat.isDebugEnabled()) {
703
	        Iterator<String> it = files.keySet().iterator();
704
	        logMetacat.debug("iterating through files");
705
	        while (it.hasNext()) {
706
	            String key = it.next();
707
	            logMetacat.debug("files key: " + key);
708
	            logMetacat.debug("files value: " + files.get(key));
709
	        }
710
711
	        it = multipartparams.keySet().iterator();
712
	        logMetacat.debug("iterating through multipartparams");
713
	        while (it.hasNext()) {
714
	            String key = (String)it.next();
715
	            logMetacat.debug("multipartparams key: " + key);
716
	            logMetacat.debug("multipartparams value: " + multipartparams.get(key));
717
	        }
718
719
	        it = params.keySet().iterator();
720
	        logMetacat.debug("iterating through params");
721
	        while (it.hasNext()) {
722
	            String key = (String)it.next();
723
	            logMetacat.debug("param key: " + key);
724
	            logMetacat.debug("param value: " + params.get(key));
725
	        }
726
	        logMetacat.debug("done iterating the request...");
727 6269 leinfelder
        }
728
729
        return files;
730
    }
731
732 6140 cjones
		/**
733 6590 cjones
     *  copies request parameters to a hashtable which is given as argument to
734
     *  native metacathandler functions
735 5374 berkley
     */
736 6247 leinfelder
    protected void initParams() {
737 5211 jones
738 5374 berkley
        String name = null;
739
        String[] value = null;
740
        Enumeration paramlist = request.getParameterNames();
741
        while (paramlist.hasMoreElements()) {
742
            name = (String) paramlist.nextElement();
743
            value = request.getParameterValues(name);
744
            params.put(name, value);
745
        }
746
    }
747 6660 leinfelder
748
    /**
749
     * Collect the multipart params from the request
750
     * @throws Exception
751
     */
752
	protected void initMultipartParams() throws Exception {
753
754
		// Read the incoming data from its Mime Multipart encoding
755
		logMetacat.debug("Disassembling MIME multipart form");
756
757
		// handle MMP inputs
758
		File tmpDir = getTempDirectory();
759
		logMetacat.debug("temp dir: " + tmpDir.getAbsolutePath());
760
		MultipartRequestResolver mrr =
761
			new MultipartRequestResolver(tmpDir.getAbsolutePath(), 1000000000, 0);
762
		MultipartRequest mr = mrr.resolveMultipart(request);
763
764
		multipartparams = mr.getMultipartParameters();
765
	}
766 6469 leinfelder
767 5211 jones
    /**
768 5808 berkley
     * locate the boundary marker for an MMP
769 5462 berkley
     * @param is
770
     * @return
771 5808 berkley
     * @throws IOException
772 5462 berkley
     */
773 5639 berkley
    protected static String[] findBoundaryString(InputStream is)
774 6268 leinfelder
        throws IOException {
775 5639 berkley
        String[] endResult = new String[2];
776 5637 berkley
        String boundary = "";
777 5639 berkley
        String searchString = "boundary=";
778 5637 berkley
        byte[] b = new byte[1024];
779 5639 berkley
        int numbytes = is.read(b, 0, 1024);
780 5826 berkley
781 5639 berkley
        while(numbytes != -1)
782 5636 berkley
        {
783 5639 berkley
            String s = new String(b, 0, numbytes);
784 5826 berkley
            int searchStringIndex = s.indexOf(searchString);
785 5639 berkley
786
            if(s.indexOf("\"", searchStringIndex + searchString.length() + 1) == -1)
787
            { //the end of the boundary is in the next byte array
788
                boundary = s.substring(searchStringIndex + searchString.length() + 1, s.length());
789
            }
790
            else if(!boundary.startsWith("--"))
791
            { //we can read the whole boundary from this byte array
792
                boundary = s.substring(searchStringIndex + searchString.length() + 1,
793
                    s.indexOf("\"", searchStringIndex + searchString.length() + 1));
794
                boundary = "--" + boundary;
795
                endResult[0] = boundary;
796
                endResult[1] = s.substring(s.indexOf("\"", searchStringIndex + searchString.length() + 1) + 1,
797
                        s.length());
798
                break;
799
            }
800
            else
801
            { //we're now reading the 2nd byte array to get the rest of the boundary
802
                searchString = "\"";
803
                searchStringIndex = s.indexOf(searchString);
804
                boundary += s.substring(0, searchStringIndex);
805
                boundary = "--" + boundary;
806
                endResult[0] = boundary;
807
                endResult[1] = s.substring(s.indexOf("\"", searchStringIndex + searchString.length() + 1) + 1,
808
                        s.length());
809
                break;
810
            }
811 5637 berkley
        }
812 5639 berkley
        return endResult;
813
    }
814
815 5808 berkley
    /**
816 5838 berkley
     * return the directory where temp files are stored
817
     * @return
818
     */
819 6248 leinfelder
    protected static File getTempDirectory()
820 5838 berkley
    {
821
        File tmpDir = null;
822 6267 leinfelder
        Logger logMetacat = Logger.getLogger(D1ResourceHandler.class);
823 6268 leinfelder
        try {
824 5639 berkley
            tmpDir = new File(PropertyService.getProperty("application.tempDir"));
825
        }
826 6268 leinfelder
        catch(PropertyNotFoundException pnfe) {
827 6267 leinfelder
            logMetacat.error("D1ResourceHandler.writeMMPPartstoFiles: " +
828 5639 berkley
                    "application.tmpDir not found.  Using /tmp instead.");
829
            tmpDir = new File("/tmp");
830
        }
831 5838 berkley
        return tmpDir;
832 5639 berkley
    }
833
834 5637 berkley
    /**
835 5211 jones
     * Prints xml response
836
     * @param message Message to be displayed
837
     * @param response Servlet response that xml message will be printed
838
     * */
839 6247 leinfelder
    protected void printError(String message, HttpServletResponse response) {
840 5211 jones
        try {
841 6267 leinfelder
            logMetacat.error("D1ResourceHandler: Printing error to servlet response: " + message);
842 5211 jones
            PrintWriter out = response.getWriter();
843
            response.setContentType("text/xml");
844
            out.println("<?xml version=\"1.0\"?>");
845
            out.println("<error>");
846
            out.println(message);
847
            out.println("</error>");
848
            out.close();
849
        } catch (IOException e) {
850
            e.printStackTrace();
851
        }
852
    }
853 5370 berkley
854 5692 berkley
    /**
855
     * serialize a D1 exception using jibx
856
     * @param e
857
     * @param out
858
     */
859 6247 leinfelder
    protected void serializeException(BaseException e, OutputStream out) {
860 5319 jones
        // TODO: Use content negotiation to determine which return format to use
861
        response.setContentType("text/xml");
862
        response.setStatus(e.getCode());
863 5512 berkley
864 6267 leinfelder
        logMetacat.error("D1ResourceHandler: Serializing exception with code " + e.getCode() + ": " + e.getMessage());
865 5512 berkley
        e.printStackTrace();
866
867 5319 jones
        try {
868
            IOUtils.write(e.serialize(BaseException.FMT_XML), out);
869
        } catch (IOException e1) {
870
            logMetacat.error("Error writing exception to stream. "
871
                    + e1.getMessage());
872
        }
873
    }
874
875 5211 jones
}