Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *  Copyright: 2000 Regents of the University of California and the
4
 *              National Center for Ecological Analysis and Synthesis
5
 *  Purpose: To test the MetaCatURL class by JUnit
6
 *    Authors: Jing Tao
7
 *
8
 *   '$Author: leinfelder $'
9
 *     '$Date: 2011-06-24 21:33:19 -0700 (Fri, 24 Jun 2011) $'
10
 * '$Revision: 6211 $'
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 2 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program; if not, write to the Free Software
24
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25
 */
26

    
27
package edu.ucsb.nceas.metacattest;
28

    
29
import edu.ucsb.nceas.MCTestCase;
30
import edu.ucsb.nceas.metacat.dataone.CrudServiceTest;
31
import edu.ucsb.nceas.metacat.properties.PropertyService;
32
import edu.ucsb.nceas.utilities.HttpMessage;
33
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
34

    
35
import junit.framework.Test;
36
import junit.framework.TestSuite;
37

    
38
import java.io.*;
39
import java.net.*;
40
import java.util.*;
41

    
42
import org.dataone.service.types.AuthToken;
43
import org.dataone.service.types.Identifier;
44

    
45
/**
46
 * A JUnit test for testing Step class processing
47
 */
48
public class MetaCatServletTest extends MCTestCase {
49
	private static String metacatURL;
50
	private String serialNumber;
51

    
52
	/* Initialize properties */
53
	static {
54
		try {
55
			metacatURL = PropertyService.getProperty("test.metacatUrl");
56
		} catch (PropertyNotFoundException pnfe) {
57
			System.err.println("Could not get property in static block: "
58
					+ pnfe.getMessage());
59
		}
60
	}
61

    
62
	/**
63
	 * Constructor to build the test
64
	 * 
65
	 * @param name
66
	 *            the name of the test method
67
	 */
68
	public MetaCatServletTest(String name) {
69
		super(name);
70
	}
71

    
72
	/**
73
	 * Constructor to build the test
74
	 * 
75
	 * @param name
76
	 *            the name of the test method
77
	 */
78
	public MetaCatServletTest(String name, String serial) {
79
		super(name);
80
		serialNumber = serial;
81
	}
82

    
83
	/**
84
	 * Establish a testing framework by initializing appropriate objects
85
	 */
86
	public void setUp() {
87

    
88
	}
89

    
90
	/**
91
	 * Release any objects after tests are complete
92
	 */
93
	public void tearDown() {
94
	}
95

    
96
	/**
97
	 * Create a suite of tests to be run together
98
	 */
99
	public static Test suite() {
100
		double number = 0;
101
		String serial = null;
102

    
103
		TestSuite suite = new TestSuite();
104
		suite.addTest(new MetaCatServletTest("initialize"));
105
		suite.addTest(new MetaCatServletTest("testLterReferralLogin"));
106
		suite.addTest(new MetaCatServletTest("testLterReferralLoginFail"));
107
		suite.addTest(new MetaCatServletTest("testOtherReferralLogin"));
108
		suite.addTest(new MetaCatServletTest("testOtherReferralLoginFail"));
109
		suite.addTest(new MetaCatServletTest("testNCEASLoginFail"));
110
		// Should put a login successfully at the end of login test
111
		// So insert or update can have cookie.
112
		suite.addTest(new MetaCatServletTest("testNCEASLogin"));
113

    
114
		// create random number for docid, so it can void repeat
115
		number = Math.random() * 100000;
116
		serial = Integer.toString(((new Double(number)).intValue()));
117
		debug("serial: " + serial);
118
		suite.addTest(new MetaCatServletTest("testInsertXMLDocument", serial));
119
		suite.addTest(new MetaCatServletTest("testReadXMLDocumentXMLFormat", serial));
120
		suite.addTest(new MetaCatServletTest("testUpdateXMLDocument", serial));
121

    
122
		suite.addTest(new MetaCatServletTest("testReadXMLDocumentHTMLFormat", serial));
123
		suite.addTest(new MetaCatServletTest("testReadXMLDocumentZipFormat", serial));
124

    
125
		suite.addTest(new MetaCatServletTest("testDeleteXMLDocument", serial));
126
		
127
		// test delete using GUID
128
		number = Math.random() * 100000;
129
		serial = Integer.toString(((new Double(number)).intValue()));
130
		suite.addTest(new MetaCatServletTest("testDeleteDocumentByGUID", serial));
131

    
132
		// insert invalid xml document
133
		number = Math.random() * 100000;
134
		serial = Integer.toString(((new Double(number)).intValue()));
135
		suite.addTest(new MetaCatServletTest("testInsertInvalidateXMLDocument", serial));
136
		// insert non well formed document
137
		number = Math.random() * 100000;
138
		serial = Integer.toString(((new Double(number)).intValue()));
139
		suite
140
				.addTest(new MetaCatServletTest("testInsertNonWellFormedXMLDocument",
141
						serial));
142

    
143
		suite.addTest(new MetaCatServletTest("testLogOut"));
144

    
145
		return suite;
146
	}
147

    
148
	/**
149
	 * Run an initial test that always passes to check that the test harness is
150
	 * working.
151
	 */
152
	public void initialize() {
153
		assertTrue(1 == 1);
154
	}
155

    
156
	/**
157
	 * Test the login to neceas succesfully
158
	 */
159
    public void testNCEASLogin() {
160
        debug("\nRunning: testNCEASLogin test");
161
        try {
162
            String user = PropertyService.getProperty("test.mcUser");
163
            String passwd = PropertyService.getProperty("test.mcPassword");
164
            assertTrue(logIn(user, passwd));
165
        } catch (PropertyNotFoundException pnfe) {
166
            fail("Could not find property: " + pnfe.getMessage());
167
        }
168
    }
169

    
170
	/**
171
	 * Test the login to neceas failed
172
	 */
173
	public void testNCEASLoginFail() {
174
		debug("\nRunning: testNCEASLoginFail test");
175
        try {
176
            String user = PropertyService.getProperty("test.mcUser");
177
            String passwd = "BogusPasswordShouldFail";
178
            assertTrue(!logIn(user, passwd));
179
        } catch (PropertyNotFoundException pnfe) {
180
            fail("Could not find property: " + pnfe.getMessage());
181
        }
182
	}
183

    
184
	/**
185
	 * Test the login to lter succesfully
186
	 */
187
	public void testLterReferralLogin() {
188
		debug("\nRunning: testLterReferralLogin test");
189
		String user = null;
190
		String passwd = null;
191
		try {
192
			user = PropertyService.getProperty("test.lterUser");
193
			passwd = PropertyService.getProperty("test.lterPassword");
194
		} catch (PropertyNotFoundException pnfe) {
195
			fail("Could not find property: " + pnfe.getMessage());
196
		}
197

    
198
		debug("Logging into lter: " + user + " : " + passwd);
199
		assertTrue(logIn(user, passwd));
200

    
201
	}
202

    
203
	/**
204
	 * Test the login to lter failed
205
	 */
206
	public void testLterReferralLoginFail() {
207
		debug("\nRunning: testLterReferralLoginFail test");
208
		String user = null;
209
    String passwd = "wrong";
210
    try {
211
      user = PropertyService.getProperty("test.lterUser");
212
    } catch (PropertyNotFoundException pnfe) {
213
      fail("Could not find property: " + pnfe.getMessage());
214
    }
215
		assertTrue(!logIn(user, passwd));
216
		// assertTrue( withProtocol.getProtocol().equals("http"));
217
	}
218

    
219
	/**
220
	 * Test the login to Other succesfully
221
	 */
222
	public void testOtherReferralLogin() {
223
		debug("\nRunning: testOtherReferralLogin test");
224
		String user = null;
225
		String passwd = null;
226
		try {
227
			user = PropertyService.getProperty("test.referralUser");
228
			passwd = PropertyService.getProperty("test.referralPassword");
229
		} catch (PropertyNotFoundException pnfe) {
230
			fail("Could not find property: " + pnfe.getMessage());
231
		}
232
		debug("logging in Other user: " + user + ":" + passwd);
233
		assertTrue(logIn(user, passwd));
234
		// assertTrue( withProtocol.getProtocol().equals("http"));
235
	}
236

    
237
	/**
238
	 * Test the login to Other failed
239
	 */
240
	public void testOtherReferralLoginFail() {
241
		debug("\nRunning: testOtherReferralLoginFail test");
242
		String user = null;
243
    String passwd = "wrong";
244
    try {
245
      user = PropertyService.getProperty("test.referralUser");
246
    } catch (PropertyNotFoundException pnfe) {
247
      fail("Could not find property: " + pnfe.getMessage());
248
    }
249
		assertTrue(!logIn(user, passwd));
250
		// assertTrue( withProtocol.getProtocol().equals("http"));
251
	}
252

    
253
	/**
254
	 * Test insert a xml document successfully
255
	 */
256
    public void testInsertXMLDocument() {
257
        debug("\nRunning: testInsertXMLDocument test");
258
        String name = null;
259
        try {
260
            String user = PropertyService.getProperty("test.mcUser");
261
            String passwd = PropertyService.getProperty("test.mcPassword");
262

    
263
            name = "john" + PropertyService.getProperty("document.accNumSeparator") + serialNumber + PropertyService.getProperty("document.accNumSeparator")
264
                    + "1";
265
            debug("insert docid: " + name);
266
            String content = "<?xml version=\"1.0\"?>" + "<!DOCTYPE acl PUBLIC \"-//ecoinformatics.org//"
267
                    + "eml-access-2.0.0beta6//EN\" \"http://pine.nceas.ucsb.edu:8080/tao/dtd/eml-access-2.0.0beta6.dtd\">"
268
                    + "<acl authSystem=\"knb\" order=\"allowFirst\">" + "<identifier>" + name + "</identifier>" + "<allow>" + "<principal>" + user
269
                    + "</principal>" + "<permission>all</permission>" + "</allow>" + "<allow>" + "<principal>public</principal>"
270
                    + "<permission>read</permission>" + "</allow>" + "</acl>";
271
            debug("xml document: " + content);
272
            assertTrue(handleXMLDocument(content, name, "insert"));
273
        } catch (PropertyNotFoundException pnfe) {
274
            fail("Could not find property: " + pnfe.getMessage());
275
        }
276
    }
277

    
278
	/**
279
	 * Test insert a invalidate xml document successfully In the String, there
280
	 * is no <!Doctype ... Public/System/>
281
	 */
282
    public void testInsertInvalidateXMLDocument() {
283
        debug("\nRunning: testInsertInvalidateXMLDocument test");
284
        String name = null;
285
        try {
286
            String user = PropertyService.getProperty("test.mcUser");
287
            String passwd = PropertyService.getProperty("test.mcPassword");
288

    
289
            name = "john" + PropertyService.getProperty("document.accNumSeparator") + serialNumber + PropertyService.getProperty("document.accNumSeparator")
290
                    + "1";
291
            debug("insert docid: " + name);
292
            String content = "<?xml version=\"1.0\"?>" + "<acl authSystem=\"knb\" order=\"allowFirst\">" + "<identifier>" + name + "</identifier>" + "<allow>"
293
                    + "<principal>" + user + "</principal>" + "<permission>all</permission>" + "</allow>" + "<allow>" + "<principal>public</principal>"
294
                    + "<permission>read</permission>" + "</allow>" + "</acl>";
295
            debug("xml document: " + content);
296
            assertTrue(handleXMLDocument(content, name, "insert"));
297
        } catch (PropertyNotFoundException pnfe) {
298
            fail("Could not find property: " + pnfe.getMessage());
299
        }
300
    }
301

    
302
	/**
303
	 * Test insert a non well-formed xml document successfully There is no
304
	 * </acl> in this string
305
	 */
306
    public void testInsertNonWellFormedXMLDocument() {
307
        debug("\nRunning: testInsertNonWellFormedXMLDocument test");
308
        String name = null;
309
        try {
310
            String user = PropertyService.getProperty("test.mcUser");
311
            String passwd = PropertyService.getProperty("test.mcPassword");
312

    
313
            name = "john" + PropertyService.getProperty("document.accNumSeparator") + serialNumber + PropertyService.getProperty("document.accNumSeparator")
314
                    + "1";
315
            debug("insert non well-formed docid: " + name);
316
            String content = "<?xml version=\"1.0\"?>" + "<acl authSystem=\"knb\" order=\"allowFirst\">" + "<identifier>" + name + "</identifier>" + "<allow>"
317
                    + "<principal>" + user + "</principal>" + "<permission>all</permission>" + "</allow>" + "<allow>" + "<principal>public</principal>"
318
                    + "<permission>read</permission>" + "</allow>";
319

    
320
            debug("xml document: " + content);
321
            assertTrue(!handleXMLDocument(content, name, "insert"));
322
        } catch (PropertyNotFoundException pnfe) {
323
            fail("Could not find property: " + pnfe.getMessage());
324
        }
325
    }
326

    
327
	/**
328
	 * Test read a xml document in xml format successfully
329
	 */
330
	public void testReadXMLDocumentXMLFormat() {
331
		debug("\nRunning: testReadXMLDocumentXMLFormat test");
332
		String name = null;
333
		try {
334
			name = "john" + PropertyService.getProperty("document.accNumSeparator")
335
					+ serialNumber
336
					+ PropertyService.getProperty("document.accNumSeparator") + "1";
337
		} catch (PropertyNotFoundException pnfe) {
338
			fail("Could not find property: " + pnfe.getMessage());
339
		}
340
		assertTrue(handleReadAction(name, "xml"));
341

    
342
	}
343

    
344
	/**
345
	 * Test read a xml document in html format successfully
346
	 */
347
	public void testReadXMLDocumentHTMLFormat() {
348
		debug("\nRunning: testReadXMLDocumentHTMLFormat test");
349
		String name = null;
350
		try {
351
			name = "john" + PropertyService.getProperty("document.accNumSeparator")
352
					+ serialNumber
353
					+ PropertyService.getProperty("document.accNumSeparator") + "1";
354
		} catch (PropertyNotFoundException pnfe) {
355
			fail("Could not find property: " + pnfe.getMessage());
356
		}
357
		assertTrue(handleReadAction(name, "html"));
358

    
359
	}
360

    
361
	/**
362
	 * Test read a xml document in zip format successfully
363
	 */
364
	public void testReadXMLDocumentZipFormat() {
365
		debug("\nRunning: testReadXMLDocumentZipFormat test");
366
		String name = null;
367
		try {
368
			name = "john" + PropertyService.getProperty("document.accNumSeparator")
369
					+ serialNumber
370
					+ PropertyService.getProperty("document.accNumSeparator") + "1";
371
		} catch (PropertyNotFoundException pnfe) {
372
			fail("Could not find property: " + pnfe.getMessage());
373
		}
374
		assertTrue(handleReadAction(name, "zip"));
375

    
376
	}
377

    
378
	/**
379
	 * Test insert a xml document successfully
380
	 */
381
    public void testUpdateXMLDocument() {
382
        debug("\nRunning: testUpdateXMLDocument test");
383
        String name = null;
384
        try {
385
            String user = PropertyService.getProperty("test.mcUser");
386
            String passwd = PropertyService.getProperty("test.mcPassword");
387

    
388
            name = "john" + PropertyService.getProperty("document.accNumSeparator") + serialNumber + PropertyService.getProperty("document.accNumSeparator")
389
                    + "2";
390
            debug("update docid: " + name);
391
            String content = "<?xml version=\"1.0\"?>" + "<!DOCTYPE acl PUBLIC \"-//ecoinformatics.org//"
392
                    + "eml-access-2.0.0beta6//EN\" \"http://pine.nceas.ucsb." + "edu:8080/tao/dtd/eml-access-2.0.0beta6.dtd\">"
393
                    + "<acl authSystem=\"knb\" order=\"allowFirst\">" + "<identifier>" + name + "</identifier>" + "<allow>" + "<principal>" + user
394
                    + "</principal>" + "<permission>all</permission>" + "</allow>" + "<allow>" + "<principal>public</principal>"
395
                    + "<permission>read</permission>" + "</allow>" + "</acl>";
396
            debug("xml document: " + content);
397
            assertTrue(handleXMLDocument(content, name, "update"));
398
        } catch (PropertyNotFoundException pnfe) {
399
            fail("Could not find property: " + pnfe.getMessage());
400
        }
401
    }
402

    
403
	/**
404
	 * Test delete a xml document successfully
405
	 */
406
	public void testDeleteXMLDocument() {
407
		debug("\nRunning: testDeleteXMLDocument test");
408
		String name = null;
409
		try {
410
			name = "john" + PropertyService.getProperty("document.accNumSeparator")
411
					+ serialNumber
412
					+ PropertyService.getProperty("document.accNumSeparator") + "2";
413
		} catch (PropertyNotFoundException pnfe) {
414
			fail("Could not find property: " + pnfe.getMessage());
415
		}
416
		debug("delete docid: " + name);
417
		assertTrue(handleDeleteFile(name));
418

    
419
	}
420

    
421
    /**
422
     * Test to delete a document by GUID (not docid).  This exercises 
423
     * MetacatServlet.handleDeleteAction()'s handling of GUIDs.
424
     */
425
    public void testDeleteDocumentByGUID() {
426
        debug("\nRunning: testDeleteDocumentByGUID test");
427

    
428
        try {
429
            String user = PropertyService.getProperty("test.mcUser");
430
            String passwd = PropertyService.getProperty("test.mcPassword");
431
            
432
            CrudServiceTest crudServiceTest = new CrudServiceTest("testDeleteDocumentByGUID");
433
            String guid = "";
434
            AuthToken token = null;
435
            String result = "";
436
            // create a document via the CRUD service to get a GUID
437
            try {
438
                token = crudServiceTest.getToken(user, passwd);
439
                String testDocument = crudServiceTest.getTestDoc();
440
                Identifier identifier = crudServiceTest.createDoc(token, testDocument);
441
                guid = identifier.getValue();
442
            } catch (Exception e) {
443
                fail("Could not create test document to delete: " + e.getMessage());
444
            }
445

    
446
            // delete the document via the Metacat servlet with the GUID
447
            try {
448
                Properties props = new Properties();
449
                props.put("action", "delete");
450
                props.put("docid", guid);
451
                props.put("sessionid", token.getToken());
452
                debug("Trying to delete by GUID: " + guid);
453
                result = getMetacatString(props);
454
            } catch (Exception e) {
455
                fail("Couldn't delete GUID: " + guid);
456
            }
457
            assertTrue(result.indexOf("<success>") > 0);
458
        } catch (PropertyNotFoundException pnfe) {
459
            fail("Could not find property: " + pnfe.getMessage());
460
        }
461
    }
462
    
463
	/**
464
	 * Test logout action
465
	 */
466
	public void testLogOut() {
467
		debug("\nRunning: testLogOut test");
468
		assertTrue(handleLogOut());
469

    
470
	}
471

    
472
	/**
473
	 * Method to hanld login action
474
	 * 
475
	 * @param usrerName,
476
	 *            the DN name of the test method
477
	 * @param passWord,
478
	 *            the passwd of the user
479
	 */
480

    
481
	public boolean logIn(String userName, String passWord) {
482
		Properties prop = new Properties();
483
		prop.put("action", "login");
484
		prop.put("qformat", "xml");
485
		prop.put("username", userName);
486
		prop.put("password", passWord);
487

    
488
		// Now contact metacat
489
		String response = getMetacatString(prop);
490
		debug("Login Message: " + response);
491
		boolean connected = false;
492
		if (response != null && response.indexOf("<login>") != -1) {
493
			connected = true;
494
		} else {
495

    
496
			connected = false;
497
		}
498

    
499
		return connected;
500
	}
501

    
502
	/**
503
	 * Method to hanld logout action
504
	 * 
505
	 * @param usrerName,
506
	 *            the DN name of the test method
507
	 * @param passWord,
508
	 *            the passwd of the user
509
	 */
510

    
511
	public boolean handleLogOut() {
512
		boolean disConnected = false;
513
		Properties prop = new Properties();
514
		prop.put("action", "logout");
515
		prop.put("qformat", "xml");
516

    
517
		String response = getMetacatString(prop);
518
		debug("Logout Message: " + response);
519
		HttpMessage.setCookie(null);
520

    
521
		if (response.indexOf("<logout>") != -1) {
522
			disConnected = true;
523
		} else {
524
			disConnected = false;
525
		}
526

    
527
		return disConnected;
528
	}
529

    
530
	/**
531
	 * Method to hanld read both xml and data file
532
	 * 
533
	 * @param docid,
534
	 *            the docid of the document want to read
535
	 * @param qformat,
536
	 *            the format of document user want to get
537
	 */
538
	public boolean handleReadAction(String docid, String qformat) {
539
		Properties prop = new Properties();
540
		String message = "";
541
		prop.put("action", "read");
542
		prop.put("qformat", qformat);
543
		prop.put("docid", docid);
544

    
545
		message = getMetacatString(prop);
546
		message = message.trim();
547
		if (message == null || message.equals("") || message.indexOf("<error>") != -1) {// there
548
																						// was
549
																						// an
550
																						// error
551

    
552
			return false;
553
		} else {// successfully
554
			return true;
555
		}
556

    
557
	}
558

    
559
	/**
560
	 * Method to hanld inset or update xml document
561
	 * 
562
	 * @param xmlDocument,
563
	 *            the content of xml qformat
564
	 * @param docid,
565
	 *            the docid of the document
566
	 * @param action,
567
	 *            insert or update
568
	 */
569
	public boolean handleXMLDocument(String xmlDocument, String docid, String action)
570

    
571
	{ // -attempt to write file to metacat
572
		String access = "no";
573
		StringBuffer fileText = new StringBuffer();
574
		StringBuffer messageBuf = new StringBuffer();
575
		String accessFileId = null;
576
		Properties prop = new Properties();
577
		prop.put("action", action);
578
		prop.put("public", access); // This is the old way of controlling access
579
		prop.put("doctext", xmlDocument);
580
		prop.put("docid", docid);
581

    
582
		String message = getMetacatString(prop);
583
		debug("Insert or Update Message: " + message);
584
		if (message.indexOf("<error>") != -1) {// there was an error
585

    
586
			return false;
587
		} else if (message.indexOf("<success>") != -1) {// the operation worked
588
			// write the file to the cache and return the file object
589
			return true;
590

    
591
		} else {// something weird happened.
592
			return false;
593
		}
594

    
595
	}
596

    
597
	public boolean handleDeleteFile(String name) {
598

    
599
		Properties prop = new Properties();
600
		prop.put("action", "delete");
601
		prop.put("docid", name);
602

    
603
		String message = getMetacatString(prop);
604
		debug("Delete Message: " + message);
605
		if (message.indexOf("<error>") != -1) {// there was an error
606

    
607
			return false;
608
		} else if (message.indexOf("<success>") != -1) {// the operation worked
609
			// write the file to the cache and return the file object
610
			return true;
611

    
612
		} else {// something weird happened.
613
			return false;
614
		}
615
	}
616

    
617
	public String getMetacatString(Properties prop) {
618
		String response = null;
619

    
620
		// Now contact metacat and send the request
621
		try {
622
			InputStreamReader returnStream = new InputStreamReader(
623
					getMetacatInputStream(prop));
624
			StringWriter sw = new StringWriter();
625
			int len;
626
			char[] characters = new char[512];
627
			while ((len = returnStream.read(characters, 0, 512)) != -1) {
628
				sw.write(characters, 0, len);
629
			}
630
			returnStream.close();
631
			response = sw.toString();
632
			sw.close();
633
		} catch (Exception e) {
634
			return null;
635
		}
636

    
637
		return response;
638
	}
639

    
640
	/**
641
	 * Send a request to Metacat
642
	 * 
643
	 * @param prop
644
	 *            the properties to be sent to Metacat
645
	 * @return InputStream as returned by Metacat
646
	 */
647
	public InputStream getMetacatInputStream(Properties prop) {
648
		InputStream returnStream = null;
649
		// Now contact metacat and send the request
650
		try {
651

    
652
			URL url = new URL(metacatURL);
653
			HttpMessage msg = new HttpMessage(url);
654
			returnStream = msg.sendPostMessage(prop);
655
			return returnStream;
656
		} catch (Exception e) {
657
			e.printStackTrace(System.err);
658

    
659
		}
660
		return returnStream;
661

    
662
	}
663

    
664
}
(10-10/24)