Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *  Copyright: 2011 Regents of the University of California and the
4
 *              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
import java.io.File;
26
import java.io.FileInputStream;
27
import java.io.FileNotFoundException;
28
import java.io.IOException;
29
import java.io.InputStream;
30
import java.io.OutputStream;
31
import java.io.PrintWriter;
32
import java.security.PrivateKey;
33
import java.security.cert.X509Certificate;
34
import java.util.Enumeration;
35
import java.util.Hashtable;
36
import java.util.Iterator;
37
import java.util.List;
38
import java.util.Map;
39
import java.util.Timer;
40

    
41
import javax.servlet.ServletContext;
42
import javax.servlet.http.HttpServletRequest;
43
import javax.servlet.http.HttpServletResponse;
44
import javax.xml.parsers.ParserConfigurationException;
45

    
46
import org.apache.commons.fileupload.FileUploadException;
47
import org.apache.commons.io.IOUtils;
48
import org.apache.log4j.Logger;
49
import org.dataone.client.auth.CertificateManager;
50
import org.dataone.mimemultipart.MultipartRequest;
51
import org.dataone.mimemultipart.MultipartRequestResolver;
52
import org.dataone.portal.PortalCertificateManager;
53
import org.dataone.service.exceptions.BaseException;
54
import org.dataone.service.exceptions.InvalidRequest;
55
import org.dataone.service.exceptions.ServiceFailure;
56
import org.dataone.service.types.v1.AccessPolicy;
57
import org.dataone.service.types.v1.Group;
58
import org.dataone.service.types.v1.Person;
59
import org.dataone.service.types.v1.Replica;
60
import org.dataone.service.types.v1.ReplicationPolicy;
61
import org.dataone.service.types.v1.Session;
62
import org.dataone.service.types.v1.Subject;
63
import org.dataone.service.types.v1.SubjectInfo;
64
import org.dataone.service.types.v1.SystemMetadata;
65
import org.dataone.service.util.ExceptionHandler;
66
import org.dataone.service.util.TypeMarshaller;
67
import org.jibx.runtime.JiBXException;
68
import org.xml.sax.SAXException;
69

    
70
import edu.ucsb.nceas.metacat.MetacatHandler;
71
import edu.ucsb.nceas.metacat.properties.PropertyService;
72
import edu.ucsb.nceas.metacat.service.SessionService;
73
import edu.ucsb.nceas.metacat.util.RequestUtil;
74
import edu.ucsb.nceas.metacat.util.SessionData;
75
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
76
/**
77
 * 
78
 * Base class for handling D1 REST calls in Metacat
79
 * 
80
 * @author leinfelder
81
 */
82
public class D1ResourceHandler {
83

    
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
    /**HTTP Verb HEAD*/
93
    public static final byte HEAD = 5;
94

    
95
    /*
96
     * API Resources
97
     */
98
    protected static final String RESOURCE_BASE_URL = "d1";
99

    
100
    protected static final String RESOURCE_OBJECTS = "object";
101
    protected static final String RESOURCE_META = "meta";
102
    protected static final String RESOURCE_LOG = "log";
103
    
104
    protected static final String RESOURCE_QUERY = "query";
105
    
106
    protected static final String RESOURCE_IS_AUTHORIZED = "isAuthorized";
107
    protected static final String RESOURCE_ACCESS_RULES = "accessRules";
108

    
109
    
110
    /*
111
     * API Functions used as URL parameters
112
     */
113
    protected static final String FUNCTION_NAME_INSERT = "insert";
114
    protected static final String FUNCTION_NAME_UPDATE = "update";
115
    
116
    protected ServletContext servletContext;
117
    protected Logger logMetacat;
118
    protected MetacatHandler handler;
119
    protected HttpServletRequest request;
120
    protected HttpServletResponse response;
121

    
122
    protected Hashtable<String, String[]> params;
123
    protected Map<String, List<String>> multipartparams;
124
    
125
    // D1 certificate-based authentication
126
    protected Session session;
127

    
128
    /**Initializes new instance by setting servlet context,request and response*/
129
    public D1ResourceHandler(ServletContext servletContext,
130
            HttpServletRequest request, HttpServletResponse response) {
131
        this.servletContext = servletContext;
132
        this.request = request;
133
        this.response = response;
134
    }
135

    
136
    /**
137
     * This function is called from REST API servlet and handles each request 
138
     * 
139
     * @param httpVerb (GET, POST, PUT or DELETE)
140
     */
141
    public void handle(byte httpVerb) {
142
        logMetacat = Logger.getLogger(D1ResourceHandler.class);
143
        try {
144
  
145
        	// initialize the session - three options
146
        	// #1
147
        	// load session from certificate in request
148
            session = CertificateManager.getInstance().getSession(request);
149
            
150
            // #2
151
            if (session == null) {
152
	        	// check for session-based certificate from the portal
153
            	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
            }
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
					// 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
						}
202
						subjectInfo.addPerson(person);
203
						session.setSubjectInfo(subjectInfo);
204
					}
205
				}
206
            }
207
			
208
            // initialize the parameters
209
            params = new Hashtable<String, String[]>();
210
            initParams();
211

    
212
            // create the handler for interacting with Metacat
213
            Timer timer = new Timer();
214
            handler = new MetacatHandler(timer);
215

    
216
        } catch (Exception e) {
217
        	// 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
        }
222
    }
223

    
224
    /**
225
     * subclasses should provide a more useful implementation
226
     * @return
227
     */
228
    protected boolean isD1Enabled() {
229
    	
230
    	return true;	
231
    }
232
    
233
    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

    
251
    /**
252
     * 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
        if ( exceptionFile != null && exceptionFile.length() > 0 ) {
309
            
310
            // deserialize the BaseException subclass
311
            exceptionFileStream = new FileInputStream(exceptionFile);
312
            try {
313
                failure = ExceptionHandler.deserializeXml(exceptionFileStream, 
314
                    "Replication failed for an unknown reason.");
315
                
316
            } 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
        }
327
        
328
        
329
        return failure;
330
        
331
    }
332

    
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
    
362

    
363
    /**
364
     * 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
                e.getMessage());
403
            
404
        } catch (Exception e) {
405
            throw new ServiceFailure("4882", "Couldn't resolve the multipart request: " +
406
                e.getMessage());
407
            
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
    
535
    protected AccessPolicy collectAccessPolicy() 
536
        throws IOException, ServiceFailure, InvalidRequest, JiBXException, 
537
        InstantiationException, IllegalAccessException, ParserConfigurationException, 
538
        SAXException  {
539
		
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
    protected SystemMetadata collectSystemMetadata() 
579
        throws IOException, FileUploadException, ServiceFailure, InvalidRequest, 
580
        JiBXException, InstantiationException, IllegalAccessException  {
581
		
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
			
595
		} catch (Exception e) {
596
		  if ( logMetacat.isDebugEnabled() ) {
597
		      e.printStackTrace();
598
		      
599
		  }
600
			throw new ServiceFailure("1202", 
601
					"Could not resolve multipart: " + e.getMessage());
602
			
603
		}
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
		SystemMetadata systemMetadata = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysmeta);
658
		return systemMetadata;
659
	}
660
    
661
    /**
662
     * Process the MMP request that includes files for each param
663
     * @return map of param key and the temp file that contains the encoded information
664
     * @throws ServiceFailure
665
     * @throws InvalidRequest
666
     */
667
    protected Map<String, File> collectMultipartFiles() 
668
        throws ServiceFailure, InvalidRequest {
669
    	
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
        logMetacat.debug("temp dir: " + tmpDir.getAbsolutePath());
676
        MultipartRequestResolver mrr = 
677
        	new MultipartRequestResolver(tmpDir.getAbsolutePath(), 1000000000, 0);
678
        MultipartRequest mr = null;
679
		    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
        logMetacat.debug("resolved multipart request");
687
        Map<String, File> files = mr.getMultipartFiles();
688
        if (files == null) {
689
            throw new ServiceFailure("1202", "no multipart files found");
690
        }
691
        logMetacat.debug("got multipart files");
692
        
693
        if (files.keySet() == null) {
694
            logMetacat.error("No file keys in MMP request.");
695
            throw new ServiceFailure("1202", "No file keys found in MMP.");
696
        }
697
        
698
        multipartparams = mr.getMultipartParameters();
699

    
700
		    // 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
        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
        }
728
        
729
        return files;
730
    }
731
    
732
		/**
733
     *  copies request parameters to a hashtable which is given as argument to 
734
     *  native metacathandler functions  
735
     */
736
    protected void initParams() {
737

    
738
        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
    
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
   
767
    /**
768
     * locate the boundary marker for an MMP
769
     * @param is
770
     * @return
771
     * @throws IOException
772
     */
773
    protected static String[] findBoundaryString(InputStream is)
774
        throws IOException {
775
        String[] endResult = new String[2];
776
        String boundary = "";
777
        String searchString = "boundary=";
778
        byte[] b = new byte[1024];
779
        int numbytes = is.read(b, 0, 1024);
780

    
781
        while(numbytes != -1)
782
        {
783
            String s = new String(b, 0, numbytes);
784
            int searchStringIndex = s.indexOf(searchString);
785
            
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
        }
812
        return endResult;
813
    }
814
    
815
    /**
816
     * return the directory where temp files are stored
817
     * @return
818
     */
819
    protected static File getTempDirectory()
820
    {
821
        File tmpDir = null;
822
        Logger logMetacat = Logger.getLogger(D1ResourceHandler.class);
823
        try {
824
            tmpDir = new File(PropertyService.getProperty("application.tempDir"));
825
        }
826
        catch(PropertyNotFoundException pnfe) {
827
            logMetacat.error("D1ResourceHandler.writeMMPPartstoFiles: " +
828
                    "application.tmpDir not found.  Using /tmp instead.");
829
            tmpDir = new File("/tmp");
830
        }
831
        return tmpDir;
832
    }
833
    
834
    /**
835
     * Prints xml response
836
     * @param message Message to be displayed
837
     * @param response Servlet response that xml message will be printed 
838
     * */
839
    protected void printError(String message, HttpServletResponse response) {
840
        try {
841
            logMetacat.error("D1ResourceHandler: Printing error to servlet response: " + message);
842
            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
    
854
    /**
855
     * serialize a D1 exception using jibx
856
     * @param e
857
     * @param out
858
     */
859
    protected void serializeException(BaseException e, OutputStream out) {
860
        // TODO: Use content negotiation to determine which return format to use
861
        response.setContentType("text/xml");
862
        response.setStatus(e.getCode());
863
        
864
        logMetacat.error("D1ResourceHandler: Serializing exception with code " + e.getCode() + ": " + e.getMessage());
865
        e.printStackTrace();
866
        
867
        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
}
(4-4/9)