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.util.RequestUtil;
73
import edu.ucsb.nceas.metacat.util.SessionData;
74
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
75
/**
76
 * 
77
 * Base class for handling D1 REST calls in Metacat
78
 * 
79
 * @author leinfelder
80
 */
81
public class D1ResourceHandler {
82

    
83
    /**HTTP Verb GET*/
84
    public static final byte GET = 1;
85
    /**HTTP Verb POST*/
86
    public static final byte POST = 2;
87
    /**HTTP Verb PUT*/
88
    public static final byte PUT = 3;
89
    /**HTTP Verb DELETE*/
90
    public static final byte DELETE = 4;
91
    /**HTTP Verb HEAD*/
92
    public static final byte HEAD = 5;
93

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

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

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

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

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

    
135
    /**
136
     * This function is called from REST API servlet and handles each request 
137
     * 
138
     * @param httpVerb (GET, POST, PUT or DELETE)
139
     */
140
    public void handle(byte httpVerb) {
141
        logMetacat = Logger.getLogger(D1ResourceHandler.class);
142
        try {
143
  
144
        	// initialize the session - three options
145
        	// #1
146
        	// load session from certificate in request
147
            session = CertificateManager.getInstance().getSession(request);
148
            
149
            // #2
150
            if (session == null) {
151
	        	// check for session-based certificate from the portal
152
	        	String configurationFileName = servletContext.getInitParameter("oa4mp:client.config.file");
153
	        	String configurationFilePath = servletContext.getRealPath(configurationFileName);
154
	        	PortalCertificateManager portalManager = new PortalCertificateManager(configurationFilePath);
155
	        	logMetacat.debug("Initialized the PortalCertificateManager using config file: " + configurationFilePath);
156
	        	X509Certificate certificate = portalManager.getCertificate(request);
157
	        	logMetacat.debug("Retrieved certificate: " + certificate);
158
		    	PrivateKey key = portalManager.getPrivateKey(request);
159
		    	logMetacat.debug("Retrieved key: " + key);
160
		    	if (certificate != null && key != null) {
161
		        	request.setAttribute("javax.servlet.request.X509Certificate", certificate);
162
		        	logMetacat.debug("Added certificate to the request: " + certificate.toString());
163
		    	}
164
		    	
165
	            // reload session from certificate that we jsut set in request
166
	            session = CertificateManager.getInstance().getSession(request);
167
            }
168
            
169
            // #3
170
            // last resort, check for Metacat sessionid
171
            if (session == null) {
172
	            SessionData sessionData = RequestUtil.getSessionData(request);
173
				if (sessionData != null) {
174
					String userName = sessionData.getUserName();
175
					String[] groupNames = sessionData.getGroupNames();
176
					Subject userSubject = new Subject();
177
					userSubject.setValue(userName);
178
					session.setSubject(userSubject);
179
					SubjectInfo subjectInfo = new SubjectInfo();
180
					Person person = new Person();
181
					person.setSubject(userSubject);
182
					if (groupNames != null && groupNames.length > 0) {
183
						for (String groupName: groupNames) {
184
							Group group = new Group();
185
							group.setGroupName(groupName);
186
							Subject groupSubject = new Subject();
187
							groupSubject.setValue(groupName);
188
							group.setSubject(groupSubject);
189
							subjectInfo.addGroup(group);
190
							person.addIsMemberOf(groupSubject);
191
						}
192
					}
193
					subjectInfo.addPerson(person);
194
					session.setSubjectInfo(subjectInfo);
195
				}
196
            }
197
			
198
            // initialize the parameters
199
            params = new Hashtable<String, String[]>();
200
            initParams();
201

    
202
            // create the handler for interacting with Metacat
203
            Timer timer = new Timer();
204
            handler = new MetacatHandler(timer);
205

    
206
        } catch (Exception e) {
207
        	// TODO: more D1 structure when failing here
208
        	response.setStatus(400);
209
            printError("Incorrect resource!", response);
210
            logMetacat.error(e.getClass() + ": " + e.getMessage(), e);
211
        }
212
    }
213

    
214
    /**
215
     * subclasses should provide a more useful implementation
216
     * @return
217
     */
218
    protected boolean isD1Enabled() {
219
    	
220
    	return true;	
221
    }
222
    
223
    protected String parseTrailing(String resource, String token) {
224
    	// get the rest
225
        String extra = null;
226
        if (resource.indexOf(token) != -1) {
227
        	// what comes after the token?
228
            extra = resource.substring(resource.indexOf(token) + token.length());
229
            // remove the slash
230
            if (extra.startsWith("/")) {
231
            	extra = extra.substring(1);
232
            }
233
            // is there anything left?
234
            if (extra.length() == 0) {
235
            	extra = null;
236
            }
237
        }
238
        return extra;
239
    }
240

    
241
    /**
242
     * Parse the BaseException information for replication status failures if any
243
     * 
244
     * @return failure  the BaseException failure, one of it's subclasses, or null
245
     * @throws ServiceFailure
246
     * @throws InvalidRequest
247
     * @throws JiBXException 
248
     * @throws IllegalAccessException 
249
     * @throws InstantiationException 
250
     * @throws IOException 
251
     */
252
    protected BaseException collectReplicationStatus() 
253
        throws ServiceFailure, InvalidRequest, IOException, 
254
        InstantiationException, IllegalAccessException, JiBXException {
255
        
256
        BaseException failure = null;
257
        File tmpDir = getTempDirectory();
258
        MultipartRequest mr = null;
259
        Map<String, File> mmFileParts = null;
260
        File exceptionFile = null;
261
        InputStream exceptionFileStream = null;
262

    
263
        // Read the incoming data from its Mime Multipart encoding
264
        logMetacat.debug("Parsing BaseException from the mime multipart entity");
265

    
266
        // handle MMP inputs
267
        MultipartRequestResolver mrr = 
268
            new MultipartRequestResolver(tmpDir.getAbsolutePath(),1000000000, 0);
269

    
270
        try {
271
            mr = mrr.resolveMultipart(request);
272
            logMetacat.debug("Resolved the replication status BaseException multipart request.");
273
            
274
        } catch (IOException e) {
275
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
276
                e.getMessage());
277
            
278
        } catch (FileUploadException e) {
279
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
280
                e.getMessage());
281
            
282
        } catch (Exception e) {
283
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
284
                e.getMessage());
285
            
286
        }
287

    
288
        // get the map of file parts
289
        mmFileParts = mr.getMultipartFiles();
290
        
291
        if ( mmFileParts == null || mmFileParts.keySet() == null) {
292
            logMetacat.debug("BaseException for setReplicationStatus is null");            
293
        }
294
        
295
        multipartparams = mr.getMultipartParameters();
296
        exceptionFile = mmFileParts.get("failure");
297
        
298
        if ( exceptionFile != null && exceptionFile.length() > 0 ) {
299
            
300
            // deserialize the BaseException subclass
301
            exceptionFileStream = new FileInputStream(exceptionFile);
302
            try {
303
                failure = ExceptionHandler.deserializeXml(exceptionFileStream, 
304
                    "Replication failed for an unknown reason.");
305
                
306
            } catch (ParserConfigurationException e) {
307
                throw new ServiceFailure("4700", "Couldn't parse the replication failure exception: " +
308
                        e.getMessage());
309
                
310
            } catch (SAXException e) {
311
                throw new ServiceFailure("4700", "Couldn't traverse the replication failure exception: " +
312
                        e.getMessage());
313
                
314
            }
315
                
316
        }
317
        
318
        
319
        return failure;
320
        
321
    }
322

    
323
    /**
324
     * Parse string parameters from the mime multipart entity of the request.
325
     * Populates the multipartparams map
326
     * 
327
     * @throws IOException
328
     * @throws FileUploadException
329
     * @throws Exception
330
     */
331
    protected void collectMultipartParams() 
332
        throws IOException, FileUploadException, Exception {
333
        
334
        File tmpDir = getTempDirectory();
335
        MultipartRequest mr = null;
336

    
337
        // Read the incoming data from its Mime Multipart encoding
338
        logMetacat.debug("Parsing rights holder info from the mime multipart entity");
339

    
340
        // handle MMP inputs
341
        MultipartRequestResolver mrr = 
342
            new MultipartRequestResolver(tmpDir.getAbsolutePath(),1000000000, 0);
343

    
344
        mr = mrr.resolveMultipart(request);
345
        logMetacat.debug("Resolved the rights holder info from the mime multipart entity.");
346
                    
347
        // we only have params in this MMP entity
348
        multipartparams = mr.getMultipartParameters();
349
                
350
    }
351
    
352

    
353
    /**
354
     * Parse the replication policy document out of the mime-multipart form data
355
     * 
356
     * @return policy  the encoded policy
357
     * @throws ServiceFailure
358
     * @throws InvalidRequest
359
     * @throws IOException
360
     * @throws InstantiationException
361
     * @throws IllegalAccessException
362
     * @throws JiBXException
363
     */
364
    protected ReplicationPolicy collectReplicationPolicy() 
365
        throws ServiceFailure, InvalidRequest, IOException, InstantiationException, 
366
        IllegalAccessException, JiBXException {
367
        
368
        ReplicationPolicy policy = null;
369
        File tmpDir = getTempDirectory();
370
        MultipartRequest mr = null;
371
        Map<String, File> mmFileParts = null;
372
        File replPolicyFile = null;
373
        InputStream replPolicyStream = null;
374
        
375
        // Read the incoming data from its Mime Multipart encoding
376
        logMetacat.debug("Parsing ReplicationPolicy from the mime multipart entity");
377

    
378
        // handle MMP inputs
379
        MultipartRequestResolver mrr = 
380
            new MultipartRequestResolver(tmpDir.getAbsolutePath(),1000000000, 0);
381
        
382
        try {
383
            mr = mrr.resolveMultipart(request);
384
            logMetacat.debug("Resolved the ReplicationPolicy multipart request.");
385
            
386
        } catch (IOException e) {
387
            throw new ServiceFailure("4882", "Couldn't resolve the multipart request: " +
388
                e.getMessage());
389
            
390
        } catch (FileUploadException e) {
391
            throw new ServiceFailure("4882", "Couldn't resolve the multipart request: " +
392
                e.getMessage());
393
            
394
        } catch (Exception e) {
395
            throw new ServiceFailure("4882", "Couldn't resolve the multipart request: " +
396
                e.getMessage());
397
            
398
        }
399
        
400
        // get the map of file parts
401
        mmFileParts = mr.getMultipartFiles();
402
        
403
        if ( mmFileParts == null || mmFileParts.keySet() == null) {
404
            throw new InvalidRequest("4883", "The multipart request must include " +
405
                "a file with the name 'policy'.");
406
            
407
        }
408
        
409
        multipartparams = mr.getMultipartParameters();
410
        replPolicyFile = mmFileParts.get("policy");
411
        
412
        if ( replPolicyFile == null ) {
413
            throw new InvalidRequest("4883", "The multipart request must include " +
414
            "a file with the name 'policy'.");
415
            
416
        }
417
        
418
        
419
        // deserialize the ReplicationPolicy
420
        replPolicyStream = new FileInputStream(replPolicyFile);
421
        policy = TypeMarshaller.unmarshalTypeFromStream(ReplicationPolicy.class, replPolicyStream);
422
        
423
        return policy;
424
        
425
    }
426

    
427
    /**
428
     * Parse the replica metadata document out of the mime-multipart form data
429
     * 
430
     * @return replica  the encoded replica
431
     * @throws ServiceFailure
432
     * @throws InvalidRequest
433
     * @throws IOException
434
     * @throws InstantiationException
435
     * @throws IllegalAccessException
436
     * @throws JiBXException
437
     */
438
    protected Replica collectReplicaMetadata() 
439
        throws ServiceFailure, InvalidRequest {
440
        
441
        Replica replica = null;
442
        File tmpDir = getTempDirectory();
443
        MultipartRequest mr = null;
444
        Map<String, File> mmFileParts = null;
445
        File replicaFile = null;
446
        InputStream replicaStream = null;
447
        
448
        // Read the incoming data from its Mime Multipart encoding
449
        logMetacat.debug("Parsing Replica from the mime multipart entity");
450

    
451
        // handle MMP inputs
452
        MultipartRequestResolver mrr = 
453
            new MultipartRequestResolver(tmpDir.getAbsolutePath(),1000000000, 0);
454
        
455
        try {
456
            mr = mrr.resolveMultipart(request);
457
            logMetacat.debug("Resolved the Replica multipart request.");
458
            
459
        } catch (IOException e) {
460
            throw new ServiceFailure("4852", "Couldn't resolve the multipart request: " +
461
                e.getMessage());
462
            
463
        } catch (FileUploadException e) {
464
            throw new ServiceFailure("4852", "Couldn't resolve the multipart request: " +
465
                    e.getMessage());
466
            
467
        } catch (Exception e) {
468
            throw new ServiceFailure("4852", "Couldn't resolve the multipart request: " +
469
                    e.getMessage());
470
            
471
        }
472
        
473
        // get the map of file parts
474
        mmFileParts = mr.getMultipartFiles();
475
        
476
        if ( mmFileParts == null || mmFileParts.keySet() == null) {
477
            throw new InvalidRequest("4853", "The multipart request must include " +
478
                "a file with the name 'replicaMetadata'.");
479
            
480
        }
481
        
482
        multipartparams = mr.getMultipartParameters();
483
        replicaFile = mmFileParts.get("replicaMetadata");
484
        
485
        if ( replicaFile == null ) {
486
            throw new InvalidRequest("4853", "The multipart request must include " +
487
            "a file with the name 'replicaMetadata'.");
488
            
489
        }
490
        
491
        
492
        // deserialize the ReplicationPolicy
493
        try {
494
            replicaStream = new FileInputStream(replicaFile);
495
        } catch (FileNotFoundException e) {
496
            throw new ServiceFailure("4852", "Couldn't find the multipart file: " +
497
                    e.getMessage());
498
            
499
        }
500
        
501
        try {
502
            replica = TypeMarshaller.unmarshalTypeFromStream(Replica.class, replicaStream);
503
        } catch (IOException e) {
504
            throw new ServiceFailure("4852", "Couldn't deserialize the replica document: " +
505
                    e.getMessage());
506
            
507
        } catch (InstantiationException e) {
508
            throw new ServiceFailure("4852", "Couldn't deserialize the replica document: " +
509
                    e.getMessage());
510
            
511
        } catch (IllegalAccessException e) {
512
            throw new ServiceFailure("4852", "Couldn't deserialize the replica document: " +
513
                    e.getMessage());
514
            
515
        } catch (JiBXException e) {
516
            throw new ServiceFailure("4852", "Couldn't deserialize the replica document: " +
517
                    e.getMessage());
518
            
519
        }
520
        
521
        return replica;
522
        
523
    }
524
    
525
    protected AccessPolicy collectAccessPolicy() 
526
        throws IOException, ServiceFailure, InvalidRequest, JiBXException, 
527
        InstantiationException, IllegalAccessException, ParserConfigurationException, 
528
        SAXException  {
529
		
530
		// Read the incoming data from its Mime Multipart encoding
531
		logMetacat.debug("Disassembling MIME multipart form");
532
		InputStream ap = null;
533

    
534
		// handle MMP inputs
535
		File tmpDir = getTempDirectory();
536
		logMetacat.debug("temp dir: " + tmpDir.getAbsolutePath());
537
		MultipartRequestResolver mrr = 
538
			new MultipartRequestResolver(tmpDir.getAbsolutePath(), 1000000000, 0);
539
		MultipartRequest mr = null;
540
		try {
541
			mr = mrr.resolveMultipart(request);
542
		} catch (Exception e) {
543
			throw new ServiceFailure("2161", 
544
					"Could not resolve multipart: " + e.getMessage());
545
		}
546
		logMetacat.debug("resolved multipart request");
547
		Map<String, File> files = mr.getMultipartFiles();
548
		if (files == null || files.keySet() == null) {
549
			throw new InvalidRequest("2163",
550
					"must have multipart file with name 'accessPolicy'");
551
		}
552
		logMetacat.debug("got multipart files");
553

    
554
		multipartparams = mr.getMultipartParameters();
555

    
556
		File apFile = files.get("accessPolicy");
557
		if (apFile == null) {
558
			throw new InvalidRequest("2163",
559
					"Missing the required file-part 'accessPolicy' from the multipart request.");
560
		}
561
		logMetacat.debug("apFile: " + apFile.getAbsolutePath());
562
		ap = new FileInputStream(apFile);
563
	
564
		AccessPolicy accessPolicy = TypeMarshaller.unmarshalTypeFromStream(AccessPolicy.class, ap);
565
		return accessPolicy;
566
	}
567
    
568
    protected SystemMetadata collectSystemMetadata() 
569
        throws IOException, FileUploadException, ServiceFailure, InvalidRequest, 
570
        JiBXException, InstantiationException, IllegalAccessException  {
571
		
572
		// Read the incoming data from its Mime Multipart encoding
573
		logMetacat.debug("Disassembling MIME multipart form");
574
		InputStream sysmeta = null;
575

    
576
		// handle MMP inputs
577
		File tmpDir = getTempDirectory();
578
		logMetacat.debug("temp dir: " + tmpDir.getAbsolutePath());
579
		MultipartRequestResolver mrr = 
580
			new MultipartRequestResolver(tmpDir.getAbsolutePath(), 1000000000, 0);
581
		MultipartRequest mr = null;
582
		try {
583
			mr = mrr.resolveMultipart(request);
584
			
585
		} catch (Exception e) {
586
		  if ( logMetacat.isDebugEnabled() ) {
587
		      e.printStackTrace();
588
		      
589
		  }
590
			throw new ServiceFailure("1202", 
591
					"Could not resolve multipart: " + e.getMessage());
592
			
593
		}
594
		logMetacat.debug("resolved multipart request");
595
		Map<String, File> files = mr.getMultipartFiles();
596
		if (files == null) {
597
			throw new ServiceFailure("1202",
598
					"register meta must have multipart file with name 'sysmeta'");
599
		}
600
		logMetacat.debug("got multipart files");
601

    
602
		if (files.keySet() == null) {
603
			logMetacat.error("No file keys in MMP request.");
604
			throw new ServiceFailure(
605
					"1202",
606
					"No file keys found in MMP.  "
607
							+ "register meta must have multipart file with name 'sysmeta'");
608
		}
609

    
610
		// for logging purposes, dump out the key-value pairs that
611
		// constitute the request
612
		// 3 types exist: request params, multipart params, and
613
		// multipart files
614
		Iterator it = files.keySet().iterator();
615
		logMetacat.debug("iterating through request parts: " + it);
616
		while (it.hasNext()) {
617
			String key = (String) it.next();
618
			logMetacat.debug("files key: " + key);
619
			logMetacat.debug("files value: " + files.get(key));
620
		}
621

    
622
		multipartparams = mr.getMultipartParameters();
623
		it = multipartparams.keySet().iterator();
624
		while (it.hasNext()) {
625
			String key = (String) it.next();
626
			logMetacat.debug("multipartparams key: " + key);
627
			logMetacat.debug("multipartparams value: " + multipartparams.get(key));
628
		}
629

    
630
		it = params.keySet().iterator();
631
		while (it.hasNext()) {
632
			String key = (String) it.next();
633
			logMetacat.debug("param key: " + key);
634
			logMetacat.debug("param value: " + params.get(key));
635
		}
636
		logMetacat.debug("done iterating the request...");
637

    
638
		File smFile = files.get("sysmeta");
639
		if (smFile == null) {
640
			throw new InvalidRequest("1102",
641
					"Missing the required file-part 'sysmeta' from the multipart request.");
642
		}
643
		logMetacat.debug("smFile: " + smFile.getAbsolutePath());
644
		sysmeta = new FileInputStream(smFile);
645
	
646
		logMetacat.debug("Commence creation...");
647
		SystemMetadata systemMetadata = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysmeta);
648
		return systemMetadata;
649
	}
650
    
651
    /**
652
     * Process the MMP request that includes files for each param
653
     * @return map of param key and the temp file that contains the encoded information
654
     * @throws ServiceFailure
655
     * @throws InvalidRequest
656
     */
657
    protected Map<String, File> collectMultipartFiles() 
658
        throws ServiceFailure, InvalidRequest {
659
    	
660
        // Read the incoming data from its Mime Multipart encoding
661
        logMetacat.debug("Disassembling MIME multipart form");
662
        
663
        // handle MMP inputs
664
        File tmpDir = getTempDirectory();
665
        logMetacat.debug("temp dir: " + tmpDir.getAbsolutePath());
666
        MultipartRequestResolver mrr = 
667
        	new MultipartRequestResolver(tmpDir.getAbsolutePath(), 1000000000, 0);
668
        MultipartRequest mr = null;
669
		    try {
670
		    	  mr = mrr.resolveMultipart(request);
671
            
672
		    } catch (Exception e) {
673
                throw new ServiceFailure("1202", 
674
                		"Could not resolve multipart files: " + e.getMessage());
675
		    }
676
        logMetacat.debug("resolved multipart request");
677
        Map<String, File> files = mr.getMultipartFiles();
678
        if (files == null) {
679
            throw new ServiceFailure("1202", "no multipart files found");
680
        }
681
        logMetacat.debug("got multipart files");
682
        
683
        if (files.keySet() == null) {
684
            logMetacat.error("No file keys in MMP request.");
685
            throw new ServiceFailure("1202", "No file keys found in MMP.");
686
        }
687
        
688
        multipartparams = mr.getMultipartParameters();
689

    
690
		    // for logging purposes, dump out the key-value pairs that constitute the request
691
		    // 3 types exist: request params, multipart params, and multipart files
692
        if (logMetacat.isDebugEnabled()) {
693
	        Iterator<String> it = files.keySet().iterator();
694
	        logMetacat.debug("iterating through files");
695
	        while (it.hasNext()) {
696
	            String key = it.next();
697
	            logMetacat.debug("files key: " + key);
698
	            logMetacat.debug("files value: " + files.get(key));
699
	        }
700
	        
701
	        it = multipartparams.keySet().iterator();
702
	        logMetacat.debug("iterating through multipartparams");
703
	        while (it.hasNext()) {
704
	            String key = (String)it.next();
705
	            logMetacat.debug("multipartparams key: " + key);
706
	            logMetacat.debug("multipartparams value: " + multipartparams.get(key));
707
	        }
708
	        
709
	        it = params.keySet().iterator();
710
	        logMetacat.debug("iterating through params");
711
	        while (it.hasNext()) {
712
	            String key = (String)it.next();
713
	            logMetacat.debug("param key: " + key);
714
	            logMetacat.debug("param value: " + params.get(key));
715
	        }
716
	        logMetacat.debug("done iterating the request...");
717
        }
718
        
719
        return files;
720
    }
721
    
722
		/**
723
     *  copies request parameters to a hashtable which is given as argument to 
724
     *  native metacathandler functions  
725
     */
726
    protected void initParams() {
727

    
728
        String name = null;
729
        String[] value = null;
730
        Enumeration paramlist = request.getParameterNames();
731
        while (paramlist.hasMoreElements()) {
732
            name = (String) paramlist.nextElement();
733
            value = request.getParameterValues(name);
734
            params.put(name, value);
735
        }
736
    }
737
    
738
    /**
739
     * Collect the multipart params from the request
740
     * @throws Exception 
741
     */
742
	protected void initMultipartParams() throws Exception {
743
		
744
		// Read the incoming data from its Mime Multipart encoding
745
		logMetacat.debug("Disassembling MIME multipart form");
746
	
747
		// handle MMP inputs
748
		File tmpDir = getTempDirectory();
749
		logMetacat.debug("temp dir: " + tmpDir.getAbsolutePath());
750
		MultipartRequestResolver mrr = 
751
			new MultipartRequestResolver(tmpDir.getAbsolutePath(), 1000000000, 0);
752
		MultipartRequest mr = mrr.resolveMultipart(request);
753
		
754
		multipartparams = mr.getMultipartParameters();
755
	}
756
   
757
    /**
758
     * locate the boundary marker for an MMP
759
     * @param is
760
     * @return
761
     * @throws IOException
762
     */
763
    protected static String[] findBoundaryString(InputStream is)
764
        throws IOException {
765
        String[] endResult = new String[2];
766
        String boundary = "";
767
        String searchString = "boundary=";
768
        byte[] b = new byte[1024];
769
        int numbytes = is.read(b, 0, 1024);
770

    
771
        while(numbytes != -1)
772
        {
773
            String s = new String(b, 0, numbytes);
774
            int searchStringIndex = s.indexOf(searchString);
775
            
776
            if(s.indexOf("\"", searchStringIndex + searchString.length() + 1) == -1)
777
            { //the end of the boundary is in the next byte array
778
                boundary = s.substring(searchStringIndex + searchString.length() + 1, s.length());
779
            }
780
            else if(!boundary.startsWith("--"))
781
            { //we can read the whole boundary from this byte array
782
                boundary = s.substring(searchStringIndex + searchString.length() + 1, 
783
                    s.indexOf("\"", searchStringIndex + searchString.length() + 1));
784
                boundary = "--" + boundary;
785
                endResult[0] = boundary;
786
                endResult[1] = s.substring(s.indexOf("\"", searchStringIndex + searchString.length() + 1) + 1,
787
                        s.length());
788
                break;
789
            }
790
            else
791
            { //we're now reading the 2nd byte array to get the rest of the boundary
792
                searchString = "\"";
793
                searchStringIndex = s.indexOf(searchString);
794
                boundary += s.substring(0, searchStringIndex);
795
                boundary = "--" + boundary;
796
                endResult[0] = boundary;
797
                endResult[1] = s.substring(s.indexOf("\"", searchStringIndex + searchString.length() + 1) + 1,
798
                        s.length());
799
                break;
800
            }
801
        }
802
        return endResult;
803
    }
804
    
805
    /**
806
     * return the directory where temp files are stored
807
     * @return
808
     */
809
    protected static File getTempDirectory()
810
    {
811
        File tmpDir = null;
812
        Logger logMetacat = Logger.getLogger(D1ResourceHandler.class);
813
        try {
814
            tmpDir = new File(PropertyService.getProperty("application.tempDir"));
815
        }
816
        catch(PropertyNotFoundException pnfe) {
817
            logMetacat.error("D1ResourceHandler.writeMMPPartstoFiles: " +
818
                    "application.tmpDir not found.  Using /tmp instead.");
819
            tmpDir = new File("/tmp");
820
        }
821
        return tmpDir;
822
    }
823
    
824
    /**
825
     * Prints xml response
826
     * @param message Message to be displayed
827
     * @param response Servlet response that xml message will be printed 
828
     * */
829
    protected void printError(String message, HttpServletResponse response) {
830
        try {
831
            logMetacat.error("D1ResourceHandler: Printing error to servlet response: " + message);
832
            PrintWriter out = response.getWriter();
833
            response.setContentType("text/xml");
834
            out.println("<?xml version=\"1.0\"?>");
835
            out.println("<error>");
836
            out.println(message);
837
            out.println("</error>");
838
            out.close();
839
        } catch (IOException e) {
840
            e.printStackTrace();
841
        }
842
    }
843
    
844
    /**
845
     * serialize a D1 exception using jibx
846
     * @param e
847
     * @param out
848
     */
849
    protected void serializeException(BaseException e, OutputStream out) {
850
        // TODO: Use content negotiation to determine which return format to use
851
        response.setContentType("text/xml");
852
        response.setStatus(e.getCode());
853
        
854
        logMetacat.error("D1ResourceHandler: Serializing exception with code " + e.getCode() + ": " + e.getMessage());
855
        e.printStackTrace();
856
        
857
        try {
858
            IOUtils.write(e.serialize(BaseException.FMT_XML), out);
859
        } catch (IOException e1) {
860
            logMetacat.error("Error writing exception to stream. " 
861
                    + e1.getMessage());
862
        }
863
    }
864

    
865
}
(4-4/9)