View Javadoc

1   /*
2    * <cvs:source>$Source: /devel/astrogrid/filestore/common/src/java/org/astrogrid/filestore/common/FileStoreMock.java,v $</cvs:source>
3    * <cvs:author>$Author: clq2 $</cvs:author>
4    * <cvs:date>$Date: 2005/01/28 10:43:58 $</cvs:date>
5    * <cvs:version>$Revision: 1.12 $</cvs:version>
6    * <cvs:log>
7    *   $Log: FileStoreMock.java,v $
8    *   Revision 1.12  2005/01/28 10:43:58  clq2
9    *   dave_dev_200501141257 (filemanager)
10   *
11   *   Revision 1.11.6.2  2005/01/15 03:46:50  dave
12   *   Added initial tests for create and modified date(s) ..
13   *
14   *   Revision 1.11.6.1  2005/01/14 21:01:33  dave
15   *   Added FileStoreDateFormat utility to handle dates in ISO format ....
16   *   Fixed the file:/// problem on Unix ...
17   *
18   *   Revision 1.11  2004/12/16 17:25:49  jdt
19   *   merge from dave-dev-200410061224-200412161312
20   *
21   *   Revision 1.9.14.11  2004/12/11 06:00:12  dave
22   *   Updates to support FileManager copy ....
23   *
24   *   Revision 1.9.14.10  2004/12/08 17:54:55  dave
25   *   Added update to FileManager client and server side ...
26   *
27   *   Revision 1.9.14.9  2004/12/08 01:58:51  dave
28   *   Adde filestore location to filemanager move ...
29   *
30   *   Revision 1.9.14.8  2004/11/06 19:12:18  dave
31   *   Refactored identifier properties ...
32   *
33   *   Revision 1.9.14.7  2004/11/02 23:20:12  dave
34   *   Added property filter and changed method names to make them FileStore specific.
35   *
36   *   Revision 1.9.14.6  2004/10/29 15:54:50  dave
37   *   Added exportInit to mock implementation ...
38   *   Added UrlGetRequest to pass into exportInit ...
39   *   Added test for exportInit and UrlGetRequest ...
40   *
41   *   Revision 1.9.14.5  2004/10/29 13:21:58  dave
42   *   Added InputStream wrapper ...
43   *
44   *   Revision 1.9.14.4  2004/10/26 11:13:11  dave
45   *   Changed transfer properties 'source' to 'location', makes more sense for PUT transfers.
46   *
47   *   Revision 1.9.14.3  2004/10/21 21:00:13  dave
48   *   Added mock://xyz URL handler to enable testing of transfer.
49   *   Implemented importInit to the mock service and created transfer tests.
50   *
51   *   Revision 1.9.14.2  2004/10/19 14:56:15  dave
52   *   Refactored config and resolver to enable multiple instances of mock implementation.
53   *   Required to implement handling of multiple FileStore(s) in FileManager.
54   *
55   *   Revision 1.9.14.1  2004/10/15 03:53:04  dave
56   *   Changed WSDD deployment to 'Application' to allow multiple mock instances.
57   *
58   *   Revision 1.9  2004/09/17 06:57:10  dave
59   *   Added commons logging to FileStore.
60   *   Updated logging properties in Community.
61   *   Fixed bug in AGINAB deployment.
62   *   Removed MySpace tests with hard coded grendel address.
63   *
64   *   Revision 1.8.16.1  2004/09/17 01:08:36  dave
65   *   Updated debug to use commons logging API ....
66   *
67   *   Revision 1.8  2004/09/02 10:25:41  dave
68   *   Updated FileStore and MySpace to handle mime type and file size.
69   *   Updated Community deployment script.
70   *
71   *   Revision 1.7.2.1  2004/09/01 02:58:07  dave
72   *   Updated to use external mime type for imported files.
73   *
74   *   Revision 1.7  2004/08/27 22:43:15  dave
75   *   Updated filestore and myspace to report file size correctly.
76   *
77   *   Revision 1.6.12.2  2004/08/26 19:41:47  dave
78   *   Updated tests to check import URL size.
79   *
80   *   Revision 1.6.12.1  2004/08/26 19:06:50  dave
81   *   Modified filestore to return file size in properties.
82   *
83   *   Revision 1.6  2004/08/18 19:00:01  dave
84   *   Myspace manager modified to use remote filestore.
85   *   Tested before checkin - integration tests at 91%.
86   *
87   *   Revision 1.5.10.3  2004/08/09 10:16:28  dave
88   *   Added resource URL to the properties.
89   *
90   *   Revision 1.5.10.2  2004/08/06 22:25:06  dave
91   *   Refactored bits and broke a few tests ...
92   *
93   *   Revision 1.5.10.1  2004/08/02 14:54:15  dave
94   *   Trying to get integration tests to run
95   *
96   *   Revision 1.5  2004/07/23 09:11:16  dave
97   *   Merged development branch, dave-dev-200407221513, into HEAD
98   *
99   *   Revision 1.4.6.1  2004/07/23 02:10:58  dave
100  *   Added IvornFactory and IvornParser
101  *
102  *   Revision 1.4  2004/07/21 18:11:55  dave
103  *   Merged development branch, dave-dev-200407201059, into HEAD
104  *
105  *   Revision 1.3.2.2  2004/07/21 16:28:16  dave
106  *   Added content properties and tests
107  *
108  *   Revision 1.3.2.1  2004/07/20 19:10:40  dave
109  *   Refactored to implement URL import
110  *
111  *   Revision 1.3  2004/07/19 23:42:07  dave
112  *   Merged development branch, dave-dev-200407151443, into HEAD
113  *
114  *   Revision 1.2.4.1  2004/07/19 19:40:28  dave
115  *   Debugged and worked around Axis Exception handling
116  *
117  *   Revision 1.2  2004/07/14 13:50:29  dave
118  *   Merged development branch, dave-dev-200406301228, into HEAD
119  *
120  *   Revision 1.1.2.7  2004/07/13 16:37:29  dave
121  *   Refactored common and client to use an array of FileProperties (more SOAP friendly)
122  *
123  *   Revision 1.1.2.6  2004/07/12 14:39:03  dave
124  *   Added server repository classes
125  *
126  *   Revision 1.1.2.5  2004/07/07 14:54:35  dave
127  *   Changed DataInfo to File Info (leaves room to use DataInfo for the more abstract VoStore interface).
128  *
129  *   Revision 1.1.2.4  2004/07/07 14:32:43  dave
130  *   Changed DataIdentifier to FileIdentifier
131  *
132  *   Revision 1.1.2.3  2004/07/07 14:24:14  dave
133  *   Changed internal class DataConrainer to FileContainer
134  *
135  *   Revision 1.1.2.2  2004/07/07 11:55:54  dave
136  *   Fixed byte array compare in tests
137  *
138  *   Revision 1.1.2.1  2004/07/05 04:50:29  dave
139  *   Created initial FileStore components
140  *
141  * </cvs:log>
142  *
143  */
144 package org.astrogrid.filestore.common ;
145 
146 import org.apache.commons.logging.Log ;
147 import org.apache.commons.logging.LogFactory ;
148 
149 import java.io.IOException  ;
150 import java.io.InputStream  ;
151 import java.io.OutputStream ;
152 import java.io.ByteArrayInputStream ;
153 import java.io.ByteArrayOutputStream ;
154 
155 import java.net.URL ;
156 import java.net.URLConnection ;
157 import java.net.MalformedURLException ;
158 
159 import java.util.Map ;
160 import java.util.HashMap ;
161 import java.util.Date ;
162 
163 import org.astrogrid.filestore.common.file.FileIdentifier ;
164 import org.astrogrid.filestore.common.file.FileProperty ;
165 import org.astrogrid.filestore.common.file.FileProperties ;
166 import org.astrogrid.filestore.common.file.FileStorePropertyFilter ;
167 
168 import org.astrogrid.filestore.common.ivorn.FileStoreIvornParser ;
169 
170 import org.astrogrid.filestore.common.transfer.TransferUtil ;
171 import org.astrogrid.filestore.common.transfer.UrlPutTransfer ;
172 import org.astrogrid.filestore.common.transfer.UrlGetTransfer ;
173 import org.astrogrid.filestore.common.transfer.TransferProperties ;
174 
175 import org.astrogrid.filestore.common.exception.FileStoreException ;
176 import org.astrogrid.filestore.common.exception.FileStoreServiceException ;
177 import org.astrogrid.filestore.common.exception.FileStoreNotFoundException ;
178 import org.astrogrid.filestore.common.exception.FileStoreIdentifierException ;
179 import org.astrogrid.filestore.common.exception.FileStoreTransferException ;
180 
181 import org.astrogrid.filestore.common.transfer.mock.Handler ;
182 import org.astrogrid.filestore.common.transfer.mock.Connector ;
183 
184 /***
185  * A mock implementation of the store service.
186  *
187  */
188 public class FileStoreMock
189 	implements FileStore
190 	{
191     /***
192      * Our debug logger.
193      *
194      */
195     private static Log log = LogFactory.getLog(FileStoreMock.class);
196 
197 	/***
198 	 * Our configuration properties.
199 	 *
200 	 */
201 	private FileStoreConfig config ;
202 
203 	/***
204 	 * Public constructor, using default values.
205 	 *
206 	 */
207 	public FileStoreMock()
208 		{
209 		this(
210 			new FileStoreConfigMock()
211 			);
212 		}
213 
214 	/***
215 	 * Public constructor, with a specific config.
216 	 *
217 	 */
218 	public FileStoreMock(FileStoreConfig config)
219 		{
220 		this.config = config ;
221 		}
222 
223 	/***
224 	 * Internal Map of data objects.
225 	 *
226 	 */
227 	protected Map map = new HashMap() ;
228 
229 	/***
230 	 * Inner class to contain data.
231 	 * Although the server will probably have something similar, this is internal to to
232 	 * the implementation, and so I havn't added it to the common classes.
233 	 *
234 	 */
235 	protected class ContainerMock
236 		{
237 		/***
238 		 * Public constructor.
239 		 * @throws FileStoreServiceException If unable to handle the request.
240 		 *
241 		 */
242 		public ContainerMock(FileProperty[] props)
243 			throws FileStoreServiceException
244 			{
245 			this(
246 				new FileProperties(
247 					props
248 					)
249 				);
250 			}
251 
252 		/***
253 		 * Public constructor.
254 		 * @param props The file properties.
255 		 * @throws FileStoreServiceException If unable to handle the request.
256 		 *
257 		 */
258 		private ContainerMock(FileProperties props)
259 			throws FileStoreServiceException
260 			{
261 			log.debug("") ;
262 			log.debug("FileStoreMock.ContainerMock(FileProperties)") ;
263 			//
264 			// Assign a new identifier.
265 			this.ident = new FileIdentifier() ;
266 			log.debug("  Ident : '" + ident + "'") ;
267 			//
268 			// Register this container.
269 			map.put(
270 				this.ident(),
271 				this
272 				) ;
273 			//
274 			// Create our properties.
275 			this.properties = new FileProperties(props) ;
276 			//
277 			// Update our properties.
278 			this.update() ;
279 			}
280 
281 		/***
282 		 * Public copy constructor.
283 		 * @throws FileStoreServiceException If unable to handle the request.
284 		 *
285 		 */
286 		public ContainerMock(ContainerMock that, FileProperties props)
287 			throws FileStoreServiceException
288 			{
289 			//
290 			// Initialise our container.
291 			this(props) ;
292 			//
293 			// Make a copy of the data.
294 			this.data = (byte[]) that.data.clone() ;
295 			//
296 			// Update our properties.
297 			this.update() ;
298 			}
299 
300 		/***
301 		 * The file create data.
302 		 *
303 		 */
304 		private Date created = new Date() ;
305 
306 		/***
307 		 * The file modified data.
308 		 *
309 		 */
310 		private Date modified = new Date() ;
311 
312 		/***
313 		 * Internal identifier.
314 		 *
315 		 */
316 		private FileIdentifier ident ;
317 
318 		/***
319 		 * Access to our identifier.
320 		 *
321 		 */
322 		public String ident()
323 			{
324 			return this.ident.toString() ;
325 			}
326 
327 		/***
328 		 * Internal data information.
329 		 *
330 		 */
331 		private FileProperties properties ;
332 
333 		/***
334 		 * Access to our properties.
335 		 *
336 		 */
337 		public FileProperties properties()
338 			{
339 			return this.properties ;
340 			}
341 
342 		/***
343 		 * Our internal byte array of data.
344 		 *
345 		 */
346 		protected byte[] data ;
347 
348 		/***
349 		 * Access to the data size.
350 		 *
351 		 */
352 		public long getSize()
353 			{
354 			log.debug("") ;
355 			log.debug("FileStoreMock.ContainerMock.getSize()") ;
356 			long size = 0L ;
357 			if (null != this.data)
358 				{
359 				size = this.data.length ;
360 				}
361 			log.debug("  Size : " + String.valueOf(size)) ;
362 			return size ;
363 			}
364 
365 		/***
366 		 * Import an array of bytes.
367 		 * @throws FileStoreServiceException If unable to handle the request.
368 		 *
369 		 */
370 		public void importBytes(byte[] bytes)
371 			throws FileStoreServiceException
372 			{
373 			//
374 			// Make a copy of the data.
375 			this.data = (byte[]) bytes.clone() ;
376 			//
377 			// Update our properties.
378 			this.update() ;
379 			}
380 
381 		/***
382 		 * Export our contents as bytes.
383 		 *
384 		 */
385 		public byte[] exportBytes()
386 			{
387 			return this.data ;
388 			}
389 
390 		/***
391 		 * Append an array of bytes.
392 		 * @throws FileStoreServiceException If unable to handle the request.
393 		 *
394 		 */
395 		public void appendBytes(byte[] extra)
396 			throws FileStoreServiceException
397 			{
398 			//
399 			// Keep a reference to our original bytes.
400 			byte[] prev = this.data ;
401 			//
402 			// Create a new byte array big enough for both.
403 			this.data = new byte[prev.length + extra.length] ;
404 			//
405 			// Transfer our original bytes.
406 			int i = 0 ;
407 			for ( ; i < prev.length ; i++)
408 				{
409 				this.data[i] = prev[i] ;
410 				}
411 			//
412 			// Transfer our extra bytes.
413 			for (int j = 0 ; j < extra.length ; i++, j++)
414 				{
415 				this.data[i] = extra[j] ;
416 				}
417 			//
418 			// Update our properties.
419 			this.update() ;
420 			}
421 
422 		/***
423 		 * Import our data from a URL.
424 		 * @throws IOException If unable to import the data.
425 		 * @throws FileStoreServiceException If unable to handle the request.
426 		 *
427 		 */
428 		public void importData(URL url)
429 			throws FileStoreServiceException, IOException
430 			{
431 			log.debug("") ;
432 			log.debug("FileStoreMock.ContainerMock.importData(URL)") ;
433 			log.debug("  URL : " + url.toString()) ;
434 			//
435 			// Open a connection to the URL.
436 			URLConnection connection = url.openConnection() ;
437 			//
438 			// Set the source URL property.
439 			this.properties.setProperty(
440 				FileProperties.TRANSFER_SOURCE_URL,
441 				url.toString()
442 				) ;
443 			//
444 			// If the content type type hasn't been set yet.
445 			// Set it from the URL connection.
446 			if (null == this.properties.getProperty(
447 				FileProperties.MIME_TYPE_PROPERTY)
448 				)
449 				{
450 				this.properties.setProperty(
451 					FileProperties.MIME_TYPE_PROPERTY,
452 					connection.getContentType()
453 					) ;
454 				}
455 			//
456 			// If the content encoding hasn't been set yet.
457 			// Set it from the URL connection.
458 			if (null == this.properties.getProperty(
459 				FileProperties.MIME_ENCODING_PROPERTY)
460 				)
461 				{
462 				this.properties.setProperty(
463 					FileProperties.MIME_ENCODING_PROPERTY,
464 					connection.getContentEncoding()
465 					) ;
466 				}
467 			//
468 			// Transfer the data from the URL.
469 			this.importData(
470 				connection.getInputStream()
471 				) ;
472 			}
473 
474 		/***
475 		 * Import our data from an InputStream.
476 		 * @throws IOException If unable to import the data.
477 		 * @throws FileStoreServiceException If unable to handle the request.
478 		 *
479 		 */
480 		public void importData(InputStream in)
481 			throws FileStoreServiceException, IOException
482 			{
483 			//
484 			// Create an output stream to transfer the data to.
485 			ByteArrayOutputStream out = new ByteArrayOutputStream() ;
486 			//
487 			// Transfer the data.
488 			TransferUtil trans = new TransferUtil(in, out) ;
489 			trans.transfer() ;
490 			//
491 			// Convert into a byte array.
492 			this.data = out.toByteArray() ;
493 			//
494 			// Update our properties.
495 			this.update() ;
496 			}
497 
498 		/***
499 		 * Update the container properties.
500 		 * @throws FileStoreServiceException If unable to handle the request.
501 		 *
502 		 */
503 		public void update()
504 			throws FileStoreServiceException
505 			{
506 			log.debug("") ;
507 			log.debug("FileStoreMock.ContainerMock.update()") ;
508 			//
509 			// Update the resource ivorn.
510 			this.properties.setStoreResourceIvorn(
511 				config.getResourceIvorn(
512 					this.ident()
513 					)
514 				) ;
515 			//
516 			// Update the resource size.
517 			this.properties.setProperty(
518 				FileProperties.CONTENT_SIZE_PROPERTY,
519 				String.valueOf(
520 					this.getSize()
521 					)
522 				) ;
523 			//
524 			// ** Update the service URL - deprecated **
525 			this.properties.setProperty(
526 				FileProperties.STORE_RESOURCE_URL,
527 				config.getResourceUrl(
528 					this.ident()
529 					).toString()
530 				) ;
531 			//
532 			// Create our date formatter.
533 			FileStoreDateFormat formatter = new FileStoreDateFormat();
534 			//
535 			// Set the create date.
536 			this.properties.setProperty(
537 				FileProperties.FILE_CREATED_DATE_PROPERTY,
538 				formatter.format(
539 					created
540 					)
541 				) ;
542 			//
543 			// Update the modified date.
544 			modified = new Date() ;
545 			//
546 			// Set the modified date.
547 			this.properties.setProperty(
548 				FileProperties.FILE_MODIFIED_DATE_PROPERTY,
549 				formatter.format(
550 					modified
551 					)
552 				) ;
553 			}
554 
555 		/***
556 		 * Create a mock URL for this container.
557 		 * @todo The Connector should contain the URL.
558 		 *
559 		 */
560 		public URL getMockUrl()
561 			{
562 			log.debug("") ;
563 			log.debug("FileStoreMock.ContainerMock.getMockUrl()") ;
564 			log.debug("  Ident : " + this.ident()) ;
565 			URL url = null ;
566 			try {
567 				//
568 				// Initialise our mock URL handler.
569 				Handler.register() ;
570 				//
571 				// Create a new mock URL for this container.
572 				url = new URL(
573 					"mock://" + this.ident()
574 					) ;
575 				log.debug("  URL   : " + url.toString()) ;
576 				}
577 			catch (Exception ouch)
578 				{
579 				log.warn("Exception while creating URL") ;
580 				log.warn("  Exception : " + ouch) ;
581 				}
582 			return url ;
583 			}
584 
585 		/***
586 		 * Create a connector for our mock URL.
587 		 * @todo The Connector should contain the URL.
588 		 * @todo The Connector should handle appends.
589 		 *
590 		 */
591 		public Connector getMockConnector()
592 			{
593 			log.debug("") ;
594 			log.debug("FileStoreMock.ContainerMock.getMockConnector()") ;
595 			log.debug("  Ident : " + this.ident()) ;
596 			//
597 			// Create our connector.
598 			Connector connector = new Connector()
599 				{
600 				public InputStream getInputStream()
601 					{
602 					log.debug("") ;
603 					log.debug("FileStoreMock.ContainerMock.Connector.getInputStream()") ;
604 					return new ByteArrayInputStream(
605 						data
606 						);
607 					}
608 				public OutputStream getOutputStream()
609 					{
610 					log.debug("") ;
611 					log.debug("FileStoreMock.ContainerMock.Connector.getOutputStream()") ;
612 					return new ByteArrayOutputStream()
613 						{
614 						public void close()
615 							throws IOException
616 							{
617 							log.debug("") ;
618 							log.debug("FileStoreMock.ContainerMock.Connector.OutputStream.close()") ;
619 							super.close() ;
620 							data = this.toByteArray() ;
621 							}
622 						} ;
623 					}
624 				} ;
625 			//
626 			// Register our connector.
627 			Handler.addConnector(
628 				this.getMockUrl(),
629 				connector
630 				);
631 			//
632 			// Return our new connector.
633 			return connector ;
634 			}
635 		}
636 
637 	/***
638 	 * Get the service identifier - used for testing.
639 	 * @return The ivo identifier for this service.
640 	 * @throws FileStoreServiceException
641 	 *
642 	 */
643 	public String identifier()
644 		throws FileStoreServiceException
645 		{
646 		return config.getServiceIvorn().toString() ;
647 		}
648 
649 	/***
650 	 * Import (store) a string of data.
651 	 * @param properties An array of FileProperties describing the imported data.
652 	 * @param data The string of data to store.
653 	 * @return An array of FileProperties describing the imported data.
654 	 * @throws FileStoreException if the data string is null.
655 	 * @throws FileStoreServiceException if unable handle the request.
656 	 *
657 	 */
658 	public FileProperty[] importString(FileProperty[] properties, String data)
659 		throws FileStoreException
660 		{
661 		log.debug("") ;
662 		log.debug("----\"----") ;
663 		log.debug("FileStoreMock.importString()") ;
664 		//
665 		// Check for null data.
666 		if (null == data)
667 			{
668 			throw new FileStoreException(
669 				"Null data"
670 				) ;
671 			}
672 		//
673 		// Convert to bytes and import that.
674 		return this.importBytes(
675 			properties,
676 			data.getBytes()
677 			) ;
678 		}
679 
680 	/***
681 	 * Import (store) a byte array of data.
682 	 * @param properties An array of FileProperties describing the imported data.
683 	 * @param data The byte array of data to store.
684 	 * @return An array of FileProperties describing the imported data.
685 	 * @throws FileStoreException if the data string is null.
686 	 * @throws FileStoreServiceException If unable to handle the request.
687 	 *
688 	 */
689 	public FileProperty[] importBytes(FileProperty[] properties, byte[] data)
690 		throws FileStoreServiceException, FileStoreException
691 		{
692 		log.debug("") ;
693 		log.debug("----\"----") ;
694 		log.debug("FileStoreMock.importBytes()") ;
695 		//
696 		// Check for null data.
697 		if (null == data)
698 			{
699 			throw new FileStoreException(
700 				"Null data"
701 				) ;
702 			}
703 		//
704 		// Create a new container.
705 		ContainerMock container = new ContainerMock(
706 			properties
707 			) ;
708 		//
709 		// Store the data in our container.
710 		container.importBytes(
711 			data
712 			) ;
713 		//
714 		// Return the container properties.
715 		return container.properties().toArray() ;
716 		}
717 
718 	/***
719 	 * Append a string to existing data.
720 	 * @param ident The internal identifier of the target.
721 	 * @param data The string to append.
722 	 * @return An array of FileProperties describing the imported data.
723 	 * @throws FileStoreIdentifierException if the identifier is null or not valid.
724 	 * @throws FileStoreNotFoundException if unable to locate the file.
725 	 * @throws FileStoreException if the string is null.
726 	 * @throws FileStoreServiceException If unable to handle the request.
727 	 *
728 	 */
729 	public FileProperty[] appendString(String ident, String data)
730 		throws FileStoreServiceException, FileStoreIdentifierException, FileStoreNotFoundException, FileStoreException
731 		{
732 		log.debug("") ;
733 		log.debug("----\"----") ;
734 		log.debug("FileStoreMock.appendString()") ;
735 		log.debug("  Ident : " + ident) ;
736 		//
737 		// Check for null data.
738 		if (null == data)
739 			{
740 			throw new FileStoreException(
741 				"Null data"
742 				) ;
743 			}
744 		//
745 		// Convert to bytes and append that.
746 		return this.appendBytes(
747 			ident,
748 			data.getBytes()
749 			) ;
750 		}
751 
752 	/***
753 	 * Append an array of bytes to existing data.
754 	 * @param ident The internal identifier of the target.
755 	 * @param data The bytes to append.
756 	 * @return An array of FileProperties describing the imported data.
757 	 * @throws FileStoreIdentifierException if the identifier is null or not valid.
758 	 * @throws FileStoreNotFoundException if unable to locate the file.
759 	 * @throws FileStoreException if the data array is null.
760 	 * @throws FileStoreServiceException If unable to handle the request.
761 	 *
762 	 */
763 	public FileProperty[] appendBytes(String ident, byte[] data)
764 		throws FileStoreServiceException, FileStoreIdentifierException, FileStoreNotFoundException, FileStoreException
765 		{
766 		log.debug("") ;
767 		log.debug("----\"----") ;
768 		log.debug("FileStoreMock.appendBytes()") ;
769 		log.debug("  Ident : " + ident) ;
770 		//
771 		// Check for null data.
772 		if (null == data)
773 			{
774 			throw new FileStoreException(
775 				"Null data"
776 				) ;
777 			}
778 		//
779 		// Check for null ident.
780 		if (null == ident)
781 			{
782 			throw new FileStoreIdentifierException() ;
783 			}
784 		//
785 		// Try to locate a matching container.
786 		ContainerMock container = (ContainerMock) map.get(ident) ;
787 		//
788 		// If we found a matching container.
789 		if (null != container)
790 			{
791 			//
792 			// Append the data to our container.
793 			container.appendBytes(
794 				data
795 				) ;
796 			//
797 			// Return the container properties.
798 			return container.properties().toArray() ;
799 			}
800 		//
801 		// If we didn't find a container.
802 		else {
803 			throw new FileStoreNotFoundException(
804 				ident
805 				) ;
806 			}
807 		}
808 
809 	/***
810 	 * Export (read) the contents of a file as a string.
811 	 * @param ident The internal identifier of the target file.
812 	 * @return The contents of a data object as a string.
813 	 * @throws FileStoreIdentifierException if the identifier is null or not valid.
814 	 * @throws FileStoreNotFoundException if unable to locate the file.
815 	 * @throws FileStoreServiceException If unable to handle the request.
816 	 *
817 	 */
818 	public String exportString(String ident)
819 		throws FileStoreServiceException, FileStoreIdentifierException, FileStoreNotFoundException
820 		{
821 		log.debug("") ;
822 		log.debug("----\"----") ;
823 		log.debug("FileStoreMock.exportString()") ;
824 		log.debug("  Ident : " + ident) ;
825 		return new String(
826 			this.exportBytes(
827 				ident
828 				)
829 			) ;
830 		}
831 
832 	/***
833 	 * Export (read) the contents of a file as a string.
834 	 * @param ident The internal identifier of the target file.
835 	 * @return The contents of a data object as a string.
836 	 * @throws FileStoreIdentifierException if the identifier is null or not valid.
837 	 * @throws FileStoreNotFoundException if unable to locate the file.
838 	 * @throws FileStoreServiceException If unable to handle the request.
839 	 *
840 	 */
841 	public byte[] exportBytes(String ident)
842 		throws FileStoreServiceException, FileStoreIdentifierException, FileStoreNotFoundException
843 		{
844 		log.debug("") ;
845 		log.debug("----\"----") ;
846 		log.debug("FileStoreMock.exportBytes()") ;
847 		log.debug("  Ident : " + ident) ;
848 		//
849 		// Check for null ident.
850 		if (null == ident)
851 			{
852 			throw new FileStoreIdentifierException() ;
853 			}
854 		//
855 		// Try to locate a matching container.
856 		ContainerMock container = (ContainerMock) map.get(ident) ;
857 		//
858 		// If we found a matching container.
859 		if (null != container)
860 			{
861 			//
862 			// Return the container contents.
863 			return container.exportBytes() ;
864 			}
865 		//
866 		// If we didn't find a container.
867 		else {
868 			throw new FileStoreNotFoundException(
869 				ident
870 				) ;
871 			}
872 		}
873 
874 	/***
875 	 * Create a local duplicate (copy) of a file.
876 	 * @param ident The internal identifier of the target file.
877 	 * @param properties An optional array of FileProperties describing the copy.
878 	 * @return An array of FileProperties describing the copied data.
879 	 * @throws FileStoreIdentifierException if the identifier is null or not valid.
880 	 * @throws FileStoreNotFoundException if unable to locate the file.
881 	 * @throws FileStoreServiceException If unable to handle the request.
882 	 *
883 	 */
884 	public FileProperty[] duplicate(String ident, FileProperty[] properties)
885 		throws FileStoreServiceException, FileStoreIdentifierException, FileStoreNotFoundException
886 		{
887 		log.debug("") ;
888 		log.debug("----\"----") ;
889 		log.debug("FileStoreMock.duplicate()") ;
890 		log.debug("  Ident : " + ident) ;
891 		//
892 		// Check for null ident.
893 		if (null == ident)
894 			{
895 			throw new FileStoreIdentifierException() ;
896 			}
897 		//
898 		// Try to locate a matching container.
899 		ContainerMock original = (ContainerMock) map.get(ident) ;
900 		//
901 		// If we found a matching container.
902 		if (null != original)
903 			{
904 			//
905 			// Merge the new info with the original.
906 			FileProperties merged = new FileProperties(
907 				original.properties()
908 				) ;
909 			merged.merge(
910 				properties,
911 				new FileStorePropertyFilter()
912 				) ;
913 			//
914 			// Create a new container.
915 			ContainerMock duplicate = new ContainerMock(
916 				original,
917 				merged
918 				) ;
919 			//
920 			// Return the container properties.
921 			return duplicate.properties().toArray() ;
922 			}
923 		//
924 		// If we didn't find a container.
925 		else {
926 			throw new FileStoreNotFoundException(
927 				ident
928 				) ;
929 			}
930 		}
931 
932 	/***
933 	 * Delete a file.
934 	 * @param ident The internal identifier of the target file.
935 	 * @return An array of FileProperties describing the deleted data.
936 	 * @throws FileStoreIdentifierException if the identifier is null or not valid.
937 	 * @throws FileStoreNotFoundException if unable to locate the file.
938 	 * @throws FileStoreServiceException If unable to handle the request.
939 	 *
940 	 */
941 	public FileProperty[] delete(String ident)
942 		throws FileStoreServiceException, FileStoreIdentifierException, FileStoreNotFoundException
943 		{
944 		log.debug("") ;
945 		log.debug("----\"----") ;
946 		log.debug("FileStoreMock.delete()") ;
947 		log.debug("  Ident : " + ident) ;
948 		//
949 		// Check for null ident.
950 		if (null == ident)
951 			{
952 			throw new FileStoreIdentifierException() ;
953 			}
954 		//
955 		// Try to locate a matching container.
956 		ContainerMock container = (ContainerMock) map.get(ident) ;
957 		//
958 		// If we found a matching container.
959 		if (null != container)
960 			{
961 			//
962 			// Remove the container from our map.
963 			map.remove(container.ident()) ;
964 			//
965 			// Return the container properties.
966 			return container.properties().toArray() ;
967 			}
968 		//
969 		// If we didn't find a container.
970 		else {
971 			throw new FileStoreNotFoundException(
972 				ident
973 				) ;
974 			}
975 		}
976 
977 	/***
978 	 * Get the meta data information for a file.
979 	 * @param ident The internal identifier of the target file.
980 	 * @return An array of FileProperties describing the data.
981 	 * @throws FileStoreIdentifierException if the identifier is null or not valid.
982 	 * @throws FileStoreNotFoundException if unable to locate the file.
983 	 * @throws FileStoreServiceException if unable handle the request.
984      * @throws RemoteException If the WebService call fails.
985 	 * @throws FileStoreServiceException If unable to handle the request.
986 	 *
987 	 */
988 	public FileProperty[] properties(String ident)
989 		throws FileStoreServiceException, FileStoreIdentifierException, FileStoreNotFoundException
990 		{
991 		log.debug("") ;
992 		log.debug("----\"----") ;
993 		log.debug("FileStoreMock.properties()") ;
994 		log.debug("  Ident : " + ident) ;
995 		//
996 		// Check for null ident.
997 		if (null == ident)
998 			{
999 			throw new FileStoreIdentifierException() ;
1000 			}
1001 		//
1002 		// Try to locate a matching container.
1003 		ContainerMock container = (ContainerMock) map.get(ident) ;
1004 		//
1005 		// If we found a matching container.
1006 		if (null != container)
1007 			{
1008 			//
1009 			// Update the properties.
1010 			container.update();
1011 			//
1012 			// Return the container properties.
1013 			return container.properties().toArray() ;
1014 			}
1015 		//
1016 		// If we didn't find a container.
1017 		else {
1018 			throw new FileStoreNotFoundException(
1019 				ident
1020 				) ;
1021 			}
1022 		}
1023 
1024 	/***
1025 	 * Prepare to receive a data object from a remote source.
1026 	 * @param transfer A TransferProperties object describing the transfer.
1027 	 * @return A new TransferProperties describing the transfer.
1028 	 * @throws FileStoreServiceException If unable to handle the request.
1029 	 * @throws FileStoreTransferException If the input transfer properties are not valid.
1030 	 *
1031 	 */
1032 	public TransferProperties importInit(TransferProperties transfer)
1033 		throws FileStoreServiceException, FileStoreTransferException
1034 		{
1035 		log.debug("") ;
1036 		log.debug("----\"----") ;
1037 		log.debug("FileStoreMock.importInit()") ;
1038 		//
1039 		// Check for null transfer properties.
1040 		if (null == transfer)
1041 			{
1042 			throw new FileStoreTransferException(
1043 				"Null transfer properties"
1044 				) ;
1045 			}
1046 		//
1047 		// Create a new container.
1048 		ContainerMock container = new ContainerMock(
1049 			transfer.getFileProperties()
1050 			) ;
1051 		//
1052 		// Get a connector for the container.
1053 		Connector connector = container.getMockConnector() ;
1054 		//
1055 		// Get the container URL.
1056 		URL url = container.getMockUrl() ;
1057 		//
1058 		// Set the transfer URL.
1059 		transfer.setLocation(url.toString()) ;
1060 		transfer.setProtocol("http") ;
1061 		transfer.setMethod("PUT") ;
1062 		//
1063 		// Update the transfer properties.
1064 		transfer.setFileProperties(
1065 			container.properties().toArray()
1066 			);
1067 		//
1068 		// Return the new transfer properties.
1069 		return transfer ;
1070 		}
1071 
1072 	/***
1073 	 * Import a data object from a remote source.
1074 	 * @param transfer A TransferProperties object describing the transfer.
1075 	 * @return A new TransferProperties describing the transfer.
1076 	 * @throws FileStoreTransferException if the transfer properties are null.
1077 	 * @throws FileStoreServiceException If unable to handle the request.
1078 	 *
1079 	 */
1080 	public TransferProperties importData(TransferProperties transfer)
1081 		throws FileStoreServiceException, FileStoreTransferException
1082 		{
1083 		log.debug("") ;
1084 		log.debug("----\"----") ;
1085 		log.debug("FileStoreMock.importData()") ;
1086 		//
1087 		// Check for null transfer properties.
1088 		if (null == transfer)
1089 			{
1090 			throw new FileStoreTransferException(
1091 				"Null transfer properties"
1092 				) ;
1093 			}
1094 		//
1095 		// Check for null URL.
1096 		if (null == transfer.getLocation())
1097 			{
1098 			throw new FileStoreTransferException(
1099 				"Null transfer source"
1100 				) ;
1101 			}
1102 		//
1103 		// Create a new container.
1104 		ContainerMock container = new ContainerMock(
1105 			transfer.getFileProperties()
1106 			) ;
1107 		//
1108 		// Transfer the data.
1109 		try {
1110 			container.importData(
1111 				new URL(
1112 					transfer.getLocation()
1113 					)
1114 				) ;
1115 			}
1116 		catch (MalformedURLException ouch)
1117 			{
1118 			throw new FileStoreTransferException(
1119 				ouch
1120 				) ;
1121 			}
1122 		catch (IOException ouch)
1123 			{
1124 			throw new FileStoreTransferException(
1125 				ouch
1126 				) ;
1127 			}
1128 		//
1129 		// Add the updated file properties.
1130 		transfer.setFileProperties(
1131 			container.properties().toArray()
1132 			) ;
1133 		//
1134 		// Return the transfer properties.
1135 		return transfer ;
1136 		}
1137 
1138 	/***
1139 	 * Prepare to send a data object to a remote destination.
1140 	 * @param transfer A TransferProperties object describing the transfer.
1141 	 * @return A new TransferProperties describing the transfer.
1142 	 * @throws FileStoreTransferException if the transfer properties are null.
1143 	 * @throws FileStoreNotFoundException If unable to locate the target object.
1144 	 * @throws FileStoreServiceException If unable to handle the request.
1145 	 *
1146 	 */
1147 	public TransferProperties exportInit(TransferProperties transfer)
1148 		throws FileStoreServiceException, FileStoreNotFoundException, FileStoreTransferException
1149 		{
1150 		log.debug("") ;
1151 		log.debug("----\"----") ;
1152 		log.debug("FileStoreMock.exportInit()") ;
1153 		//
1154 		// Check for null transfer properties.
1155 		if (null == transfer)
1156 			{
1157 			throw new FileStoreTransferException(
1158 				"Null transfer properties"
1159 				) ;
1160 			}
1161 		//
1162 		// Get the transfer file properties.
1163 		FileProperties properties = new FileProperties(
1164 			transfer.getFileProperties()
1165 			) ;
1166 		//
1167 		// Get the file identifier.
1168 		String ident = null ;
1169 		try {
1170 			ident = properties.getStoreResourceIdent();
1171 			}
1172 		catch (FileStoreIdentifierException ouch)
1173 			{
1174 			throw new FileStoreNotFoundException(
1175 				"Unable to parse resource identifier"
1176 				) ;
1177 			}
1178 		log.debug("  Ident : " + ident) ;
1179 		//
1180 		// Try to locate our container.
1181 		ContainerMock container = (ContainerMock) map.get(ident) ;
1182 		//
1183 		// If we found a matching container.
1184 		if (null != container)
1185 			{
1186 			//
1187 			// Register our mock URL connector.
1188 			container.getMockConnector() ;
1189 			//
1190 			// Create a new transfer properties.
1191 			transfer = new UrlGetTransfer(
1192 				container.getMockUrl(),
1193 				container.properties()
1194 				) ;
1195 			//
1196 			// Return the new transfer properties.
1197 			return transfer ;
1198 			}
1199 		//
1200 		// If we didn't find a container.
1201 		else {
1202 			throw new FileStoreNotFoundException(
1203 				ident
1204 				) ;
1205 			}
1206 		}
1207 
1208 	/***
1209 	 * Export a data object to a remote destination.
1210 	 * @param transfer A TransferProperties object describing the transfer.
1211 	 * @return A new TransferProperties describing the transfer.
1212 	 *
1213 	 */
1214 	public TransferProperties exportData(TransferProperties transfer)
1215 		{
1216 		return transfer ;
1217 		}
1218 
1219 	/***
1220 	 * Throw a FileStoreIdentifierException, useful for debugging the transfer of Exceptions via SOAP.
1221 	 * @throws FileStoreIdentifierException as requested.
1222 	 *
1223 	 */
1224 	public void throwIdentifierException()
1225 		throws FileStoreIdentifierException
1226 		{
1227 		throw new FileStoreIdentifierException(
1228 			"TEST FAULT",
1229 			"TEST IDENT"
1230 			) ;
1231 		}
1232 
1233 
1234 	}
1235