View Javadoc

1   /*
2    * <cvs:source>$Source: /devel/astrogrid/filemanager/client/src/java/org/astrogrid/filemanager/client/delegate/FileManagerDelegateNode.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.2 $</cvs:version>
6    * <cvs:log>
7    *   $Log: FileManagerDelegateNode.java,v $
8    *   Revision 1.2  2005/01/28 10:43:58  clq2
9    *   dave_dev_200501141257 (filemanager)
10   *
11   *   Revision 1.1.2.2  2005/01/26 12:24:20  dave
12   *   Removed type from add(), replaced with addNode() and addFile() ...
13   *
14   *   Revision 1.1.2.1  2005/01/22 07:54:16  dave
15   *   Refactored delegate into a separate package ....
16   *
17   *   Revision 1.4.2.6  2005/01/21 14:41:58  dave
18   *   Added importData(URL url) to the API (needs implementation and tests).
19   *
20   *   Revision 1.4.2.5  2005/01/21 13:07:37  dave
21   *   Added exportURL to the node API ...
22   *
23   *   Revision 1.4.2.4  2005/01/21 12:18:54  dave
24   *   Changed input() and output() to exportStream() and importStream() ...
25   *
26   *   Revision 1.4.2.3  2005/01/19 11:39:28  dave
27   *   Added combined create and modify date ...
28   *
29   *   Revision 1.4.2.2  2005/01/18 14:52:48  dave
30   *   Added node create and modify dates ..
31   *
32   *   Revision 1.4.2.1  2005/01/15 08:25:20  dave
33   *   Added file create and modify dates to manager and client API ...
34   *
35   *   Revision 1.4  2005/01/13 17:23:15  jdt
36   *   merges from dave-dev-200412201250
37   *
38   *   Revision 1.3.4.2  2005/01/12 14:20:57  dave
39   *   Replaced tabs with spaces ....
40   *
41   *   Revision 1.3.4.1  2005/01/07 12:18:00  dave
42   *   Added StoreClientWrapperTest
43   *   Added StoreFileWrapper
44   *
45   *   Revision 1.3  2004/12/16 17:25:49  jdt
46   *   merge from dave-dev-200410061224-200412161312
47   *
48   *   Revision 1.1.2.14  2004/12/14 10:39:17  dave
49   *   Added copy to node API ....
50   *
51   *   Revision 1.1.2.13  2004/12/14 10:32:18  dave
52   *   Added copy to node API ....
53   *
54   *   Revision 1.1.2.12  2004/12/11 01:57:30  dave
55   *   Added automatic trigger to node update() on OutputStream close() ....
56   *
57   *   Revision 1.1.2.11  2004/12/10 05:21:25  dave
58   *   Added node and iterator to client API ...
59   *
60   *   Revision 1.1.2.10  2004/12/08 17:54:55  dave
61   *   Added update to FileManager client and server side ...
62   *
63   *   Revision 1.1.2.9  2004/12/08 01:56:04  dave
64   *   Added filestore location to move ...
65   *
66   *   Revision 1.1.2.8  2004/12/04 05:22:21  dave
67   *   Fixed null parent mistake ...
68   *
69   *   Revision 1.1.2.7  2004/12/02 19:11:54  dave
70   *   Added move name and parent to manager ...
71   *
72   *   Revision 1.1.2.6  2004/11/29 18:05:07  dave
73   *   Refactored methods names ....
74   *   Added stubs for delete, copy and move.
75   *
76   *   Revision 1.1.2.5  2004/11/25 13:41:14  dave
77   *   Added export stream handling to node ...
78   *
79   *   Revision 1.1.2.4  2004/11/24 19:23:29  dave
80   *   Started to add input and output streams to node ...
81   *
82   *   Revision 1.1.2.3  2004/11/24 16:15:08  dave
83   *   Added node functions to client ...
84   *
85   *   Revision 1.1.2.2  2004/11/16 03:26:14  dave
86   *   Added initial tests for adding accounts, containers and files ...
87   *
88   *   Revision 1.1.2.1  2004/11/13 01:41:26  dave
89   *   Created initial client API ....
90   *
91   * </cvs:log>
92   *
93   */
94  package org.astrogrid.filemanager.client.delegate ;
95  
96  import org.apache.commons.logging.Log ;
97  import org.apache.commons.logging.LogFactory ;
98  
99  import java.net.URL ;
100 
101 import java.util.Date ;
102 import java.util.List ;
103 import java.util.Iterator ;
104 
105 import java.io.IOException ;
106 import java.io.InputStream ;
107 import java.io.OutputStream ;
108 
109 import org.astrogrid.store.Ivorn ;
110 
111 import org.astrogrid.filestore.common.file.FileProperty;
112 import org.astrogrid.filestore.common.FileStoreInputStream;
113 import org.astrogrid.filestore.common.FileStoreOutputStream;
114 import org.astrogrid.filestore.common.transfer.TransferUtil;
115 import org.astrogrid.filestore.common.transfer.TransferProperties;
116 import org.astrogrid.filestore.common.exception.FileStoreIdentifierException ;
117 
118 import org.astrogrid.filemanager.common.FileManagerProperties;
119 import org.astrogrid.filemanager.common.exception.NodeNotFoundException ;
120 import org.astrogrid.filemanager.common.exception.DuplicateNodeException;
121 import org.astrogrid.filemanager.common.exception.FileManagerIdentifierException;
122 import org.astrogrid.filemanager.common.exception.FileManagerServiceException;
123 import org.astrogrid.filemanager.common.exception.FileManagerPropertiesException;
124 
125 import org.astrogrid.filemanager.client.FileManagerNode;
126 
127 /***
128  * Client implementation of the FileManagerNode interface.
129  *
130  */
131 public class FileManagerDelegateNode
132     implements FileManagerNode
133     {
134 
135     /***
136      * Our debug logger.
137      *
138      */
139     protected static Log log = LogFactory.getLog(FileManagerDelegateNode.class);
140 
141     /***
142      * A reference to the FileManagerDelegate that created this node.
143      *
144      */
145     private FileManagerCoreDelegate delegate ;
146 
147     /***
148      * Protected constructor from an array of file properties.
149      * @param delegate A reference to the FileManagerDelegate that created this node.
150      * @param properties An array of properties for the node.
151      *
152      */
153     protected FileManagerDelegateNode(FileManagerCoreDelegate delegate, FileProperty[] properties)
154         {
155         this(
156             delegate,
157             new FileManagerProperties(
158                 properties
159                 )
160             );
161         }
162 
163     /***
164      * Protected constructor from a FileManagerProperties map.
165      * @param delegate A reference to the FileManagerDelegate that created this node.
166      * @param properties An array of properties for the node.
167      *
168      */
169     protected FileManagerDelegateNode(FileManagerCoreDelegate delegate, FileManagerProperties properties)
170         {
171         if (null == delegate)
172             {
173             throw new IllegalArgumentException(
174                 "Null delegate"
175                 );
176             }
177         if (null == properties)
178             {
179             throw new IllegalArgumentException(
180                 "Null properties"
181                 );
182             }
183         this.delegate = delegate ;
184         this.properties = properties ;
185         }
186 
187     /***
188      * Our node properties.
189      *
190      */
191     private FileManagerProperties properties ;
192 
193     /***
194      * Get the node ivorn.
195      * @return The ivorn identifier for this node.
196      * @throws FileManagerIdentifierException If the ivorn is invalid.
197      *
198      */
199     public Ivorn ivorn()
200         throws FileManagerIdentifierException
201         {
202         return properties.getManagerResourceIvorn();
203         }
204 
205     /***
206      * Get the node name.
207      * @return The name for this node.
208      *
209      */
210     public String name()
211         {
212         return properties.getManagerResourceName();
213         }
214 
215     /***
216      * Get the content size for a data node.
217      * @return The size of the stored data for a data node, or -1 for a container node.
218      *
219      */
220     public long size()
221         {
222         return properties.getContentSize();
223         }
224 
225 
226     /***
227      * Get the data file create date.
228      * @return The file create date, if the node has stored data, or null if the node does not contains any data.
229      *
230      */
231     public Date getFileCreateDate()
232         {
233         return properties.getFileCreateDate();
234         }
235 
236     /***
237      * Get the data file modified date.
238      * @return The file modified date, if the node has stored data, or null if the node does not contains any data.
239      *
240      */
241     public Date getFileModifyDate()
242         {
243         return properties.getFileModifyDate();
244         }
245 
246     /***
247      * Get the node create date.
248      * @return The node create date.
249      *
250      */
251     public Date getNodeCreateDate()
252         {
253         return properties.getNodeCreateDate();
254         }
255 
256     /***
257      * Get the node modified date.
258      * @return The node modified date.
259      *
260      */
261     public Date getNodeModifyDate()
262         {
263         return properties.getNodeModifyDate();
264         }
265 
266     /***
267      * Get the create date.
268      * @return The create date.
269      *
270      */
271     public Date getCreateDate()
272         {
273         return getNodeCreateDate();
274         }
275 
276     /***
277      * Get the modified date.
278      * This returns whichever is the most recent modified date, for the node or the file.
279      * @return The modified date.
280      *
281      */
282     public Date getModifyDate()
283         {
284         Date node = getNodeModifyDate();
285         Date file = getFileModifyDate();
286         if (null != file)
287             {
288             if (file.after(node))
289                 {
290                 return file ;
291                 }
292             else {
293                 return node ;
294                 }
295             }
296         else {
297             return node ;
298             }
299         }
300 
301     /***
302      * Get the node (FileStore) location of the node data.
303      * This returns the (FileStore) location where the data is actually stored.
304      * @return The Ivorn for the (FileStore) location where the data is currently stored, or null if the node does not contain any data.
305      * @throws UnsupportedOperationException If the node represents a container (although future extensions may allow this).
306      * @throws FileManagerIdentifierException If the location Ivorn is not valid.
307      *
308      */
309     public Ivorn location()
310         throws UnsupportedOperationException, FileManagerIdentifierException
311         {
312         return properties.getManagerLocationIvorn();
313         }
314 
315     /***
316      * Get the parent node.
317      * @return The parent node, or null for a root node.
318      * @throws NodeNotFoundException If the node is not in the database.
319      * @throws FileManagerServiceException If a problem occurs when handling the request.
320      * @todo Check for an existing node in the local cache.
321      *
322      */
323     public FileManagerNode parent()
324         throws NodeNotFoundException, FileManagerServiceException
325         {
326         try {
327             return delegate.getNode(
328                 properties.getManagerParentIvorn()
329                 );
330             }
331         catch(FileManagerIdentifierException ouch)
332             {
333             throw new FileManagerServiceException(
334                 ouch.getMessage()
335                 );
336             }
337         }
338 
339     /***
340      * Check if this represents a file.
341      * @return true if this represents a file.
342      *
343      */
344     public boolean isFile()
345         {
346         return FileManagerProperties.DATA_NODE_TYPE.equals(
347             properties.getManagerResourceType()
348             ) ;
349         }
350 
351     /***
352      * Check if this represents a container.
353      * @return true if this represents a container.
354      *
355      */
356     public boolean isContainer()
357         {
358         return FileManagerProperties.CONTAINER_NODE_TYPE.equals(
359             properties.getManagerResourceType()
360             ) ;
361         }
362 
363     /***
364      * Delete this node.
365      * @throws NodeNotFoundException If the node is not in the database.
366      * @throws FileManagerServiceException If a problem occurs when handling the request.
367      *
368      */
369     public void delete()
370         throws NodeNotFoundException, FileManagerServiceException
371         {
372         }
373 
374     /***
375      * Add a new child node.
376      * @param name The node name.
377      * @return A new node for the container.
378      * @throws UnsupportedOperationException If this node represents a file.
379      * @throws DuplicateNodeException If a node with the same name already exists.
380      * @throws NodeNotFoundException If the current node is no longer in the database.
381      * @throws FileManagerServiceException If a problem occurs when handling the request.
382      *
383      */
384     public FileManagerNode addNode(String name)
385         throws
386         	UnsupportedOperationException,
387         	NodeNotFoundException,
388         	DuplicateNodeException,
389         	FileManagerServiceException
390 		{
391 		return this.add(
392 			name,
393 			FileManagerProperties.CONTAINER_NODE_TYPE
394 			);
395 		}
396 
397     /***
398      * Add a new file node.
399      * @param name The node name.
400      * @return A new node for the file.
401      * @throws UnsupportedOperationException If this node represents a file.
402      * @throws DuplicateNodeException If a node with the same name already exists.
403      * @throws NodeNotFoundException If the current node is no longer in the database.
404      * @throws FileManagerServiceException If a problem occurs when handling the request.
405      *
406      */
407     public FileManagerNode addFile(String name)
408         throws
409         	UnsupportedOperationException,
410         	NodeNotFoundException,
411         	DuplicateNodeException ,
412         	FileManagerServiceException
413 		{
414 		return this.add(
415 			name,
416 			FileManagerProperties.DATA_NODE_TYPE
417 			);
418 		}
419 
420     /***
421      * Add a new child node.
422      * @param name The node name.
423      * @param type The node type (either DATA_NODE_TYPE or CONTAINER_NODE_TYPE).
424      * @return A new node for the container.
425      * @throws UnsupportedOperationException If this node represents a file.
426      * @throws DuplicateNodeException If a node with the same name already exists.
427      * @throws NodeNotFoundException If the current node is no longer in the database.
428      * @throws FileManagerServiceException If a problem occurs when handling the request.
429      * @see FileManagerProperties.DATA_NODE_TYPE
430      * @see FileManagerProperties.CONTAINER_NODE_TYPE
431      *
432      */
433     protected FileManagerNode add(String name, String type)
434         throws UnsupportedOperationException, NodeNotFoundException, DuplicateNodeException , FileManagerServiceException
435         {
436         if (null == name)
437             {
438             throw new IllegalArgumentException(
439                 "Null node name"
440                 );
441             }
442         if (null == type)
443             {
444             throw new IllegalArgumentException(
445                 "Null node type"
446                 );
447             }
448         if (!this.isContainer())
449             {
450             throw new UnsupportedOperationException(
451                 "Node is not a container."
452                 );
453             }
454         try {
455             return delegate.add(
456                 this,
457                 name,
458                 type
459                 ) ;
460             }
461         catch (FileManagerIdentifierException ouch)
462             {
463             throw new FileManagerServiceException(
464                 "Invalid parent node identifier"
465                 );
466             }
467         }
468 
469     /***
470      * Get a child node by path.
471      * @param path The path to the child node.
472      * @return A reference to the child node.
473      * @throws UnsupportedOperationException If this node represents a file.
474      * @throws NodeNotFoundException If the node is not in the database.
475      * @throws FileManagerServiceException If a problem occurs when handling the request.
476      *
477      */
478     public FileManagerNode child(String path)
479         throws UnsupportedOperationException, NodeNotFoundException, FileManagerServiceException
480         {
481         if (null == path)
482             {
483             throw new IllegalArgumentException(
484                 "Null path"
485                 );
486             }
487         if (!this.isContainer())
488             {
489             throw new UnsupportedOperationException(
490                 "Node is not a container."
491                 );
492             }
493         try {
494             return delegate.getChild(
495                 this,
496                 path
497                 ) ;
498             }
499         catch (FileManagerIdentifierException ouch)
500             {
501             throw new FileManagerServiceException(
502                 "Invalid parent node identifier"
503                 );
504             }
505         }
506 
507     /***
508      * Open a java OutputStream to send (import) data into the node.
509      * @return An OutputStream connected directly to the node store.
510      * @throws IOException If a problem occurs openning the stream.
511      * @throws UnsupportedOperationException If the node represents a container.
512      * @throws NodeNotFoundException If the node is not in the database.
513      * @throws FileManagerServiceException If a problem occurs when handling the request.
514      *
515      */
516     public OutputStream importStream()
517         throws
518             IOException,
519             UnsupportedOperationException,
520             NodeNotFoundException,
521             FileManagerServiceException
522         {
523         if (!this.isFile())
524             {
525             throw new UnsupportedOperationException(
526                 "Node is not a file."
527                 );
528             }
529         //
530         // Call our delegate to initiate the import.
531         try {
532             TransferProperties transfer =
533                 delegate.importInit(
534                     this.properties
535                     ) ;
536             //
537             // Check we got a transfer location (URL).
538             if (null != transfer.getLocation())
539                 {
540                 //
541                 // Open an output stream to the target.
542                 FileStoreOutputStream stream = new FileStoreOutputStream(
543                     transfer.getLocation()
544                     )
545                     {
546                     public void close()
547                         throws IOException
548                         {
549                         super.close();
550                         try {
551                             refresh();
552                             }
553                         catch (Exception ouch)
554                             {
555                             log.warn("Exception in refresh() following IOStream close()");
556                             }
557                         }
558                     } ;
559                 stream.open() ;
560                 return stream ;
561                 }
562             //
563             // If we didn't get a transfer location (URL).
564             else {
565                 throw new FileManagerServiceException(
566                     "Unable to get transfer location (URL)"
567                     );
568                 }
569             }
570         catch (FileManagerPropertiesException ouch)
571             {
572             throw new FileManagerServiceException(
573                 "Unable to get transfer location (URL)",
574                 ouch
575                 );
576             }
577         }
578 
579     /***
580      * Open a java InputStream to read (export) data from the node.
581      * @return An InputStream connected directly to the node store.
582      * @throws IOException If a problem occurs openning the stream.
583      * @throws UnsupportedOperationException If the node represents a container.
584      * @throws NodeNotFoundException If the node is not in the database.
585      * @throws FileManagerServiceException If a problem occurs when handling the request.
586      *
587      */
588     public InputStream exportStream()
589         throws
590             IOException,
591             UnsupportedOperationException,
592             NodeNotFoundException,
593             FileManagerServiceException
594         {
595         //
596         // Open an output stream to the target.
597         FileStoreInputStream stream = new FileStoreInputStream(
598             exportURL()
599             ) ;
600         stream.open() ;
601         return stream ;
602         }
603 
604     /***
605      * Get a URL to access the node data from.
606      * @return A URL which connects directly to the node store.
607      * @throws UnsupportedOperationException If the node represents a container.
608      * @throws NodeNotFoundException If the node is not in the database.
609      * @throws FileManagerServiceException If a problem occurs when handling the request.
610      *
611      */
612     public URL exportURL()
613         throws
614             UnsupportedOperationException,
615             NodeNotFoundException,
616             FileManagerServiceException
617         {
618         if (!this.isFile())
619             {
620             throw new UnsupportedOperationException(
621                 "Not a data node."
622                 );
623             }
624         //
625         // Call our delegate to initiate the export.
626         try {
627             TransferProperties transfer =
628                 delegate.exportInit(
629                     this.properties
630                     ) ;
631             //
632             // Check we got a transfer location (URL).
633             if (null != transfer.getLocation())
634                 {
635                 try {
636                     return new URL(
637                         transfer.getLocation()
638                         );
639                     }
640                 catch (Exception ouch)
641                     {
642                     throw new FileManagerServiceException(
643                         "Unable to get transfer location (URL)",
644                         ouch
645                         );
646                     }
647                 }
648             //
649             // If we didn't get a transfer location (URL).
650             else {
651                 throw new FileManagerServiceException(
652                     "Unable to get transfer location (URL)"
653                     );
654                 }
655             }
656         catch (FileManagerPropertiesException ouch)
657             {
658             throw new FileManagerServiceException(
659                 "Unable to get transfer location (URL)",
660                 ouch
661                 );
662             }
663         }
664 
665     /***
666      * Import data from a URL.
667      * @throws UnsupportedOperationException If the node represents a container.
668      * @throws NodeNotFoundException If the node is not in the database.
669      * @throws FileManagerServiceException If a problem occurs when handling the request.
670      *
671      */
672     public void importData(URL url)
673         throws UnsupportedOperationException, NodeNotFoundException, FileManagerServiceException
674         {
675         throw new UnsupportedOperationException(
676             "Not implemented yet ..."
677             );
678         }
679 
680 
681     /***
682      * Create a copy of this node.
683      * If the node already has stored data, then this will create a copy of the data.
684      * @return A reference to the new node.
685      * @param name  The name of the new Node.
686      * @param node  The new parent Node in the metadata tree (null to create the new node in the same location in the tree).
687      * @param store The Ivorn of the FileStore for new Node (null to store the copy at the same location).
688      * @throws DuplicateNodeException If a node with the same name already exists in the metadata tree.
689      * @throws NodeNotFoundException If the current node is no longer in the database.
690      * @throws NodeNotFoundException If the new parent node is no longer in the database.
691      * @throws FileManagerServiceException If a problem occurs when handling the request.
692      *
693      */
694     public FileManagerNode copy(String name, FileManagerNode parent, Ivorn location)
695         throws DuplicateNodeException, NodeNotFoundException, FileManagerServiceException
696         {
697         FileManagerProperties request = new FileManagerProperties();
698         try {
699             request.setManagerResourceIvorn(
700                 this.ivorn()
701                 );
702             }
703         catch (FileManagerIdentifierException ouch)
704             {
705             throw new FileManagerServiceException(
706                 "Unable to parse node ivorn"
707                 );
708             }
709         if (null != name)
710             {
711             request.setManagerResourceName(
712                 name
713                 );
714             }
715         if (null != parent)
716             {
717             try {
718                 request.setManagerParentIvorn(
719                     parent.ivorn()
720                     );
721                 }
722             catch (FileManagerIdentifierException ouch)
723                 {
724                 throw new FileManagerServiceException(
725                     "Unable to parse parent node ivorn"
726                     );
727                 }
728             }
729         if (null != location)
730             {
731             request.setManagerLocationIvorn(
732                 location
733                 );
734             }
735         try {
736             return delegate.copy(
737                 request
738                 );
739             }
740         catch (FileManagerPropertiesException ouch)
741             {
742             throw new FileManagerServiceException(
743                 "Error in client code, invalid request properties"
744                 );
745             }
746         }
747 
748     /***
749      * Move this node to a new location.
750      * If the node already has stored data, then this may involve transfering the data to a new location.
751      * @param name  The name of the new Node.
752      * @param node  The new parent Node in the metadata tree (null to leave the node in the same location in the tree).
753      * @param store The Ivorn of the FileStore location (null to leave the data at the same location).
754      * @throws DuplicateNodeException If a node with the same name already exists in the metadata tree.
755      * @throws NodeNotFoundException If the current node is no longer in the database.
756      * @throws NodeNotFoundException If the new parent node is no longer in the database.
757      * @throws FileManagerServiceException If a problem occurs when handling the request.
758      *
759      */
760     public void move(String name, FileManagerNode parent, Ivorn location)
761         throws DuplicateNodeException, NodeNotFoundException, FileManagerServiceException
762         {
763         FileManagerProperties request = new FileManagerProperties();
764         try {
765             request.setManagerResourceIvorn(
766                 this.ivorn()
767                 );
768             }
769         catch (FileManagerIdentifierException ouch)
770             {
771             throw new FileManagerServiceException(
772                 "Unable to parse node ivorn"
773                 );
774             }
775         if (null != name)
776             {
777             request.setManagerResourceName(
778                 name
779                 );
780             }
781         if (null != parent)
782             {
783             try {
784                 request.setManagerParentIvorn(
785                     parent.ivorn()
786                     );
787                 }
788             catch (FileManagerIdentifierException ouch)
789                 {
790                 throw new FileManagerServiceException(
791                     "Unable to parse parent node ivorn"
792                     );
793                 }
794             }
795         if (null != location)
796             {
797             request.setManagerLocationIvorn(
798                 location
799                 );
800             }
801         try {
802             this.properties = new FileManagerProperties(
803                 delegate.move(
804                     request
805                     )
806                 );
807             }
808         catch (FileManagerPropertiesException ouch)
809             {
810             throw new FileManagerServiceException(
811                 "Error in client code, invalid request properties"
812                 );
813             }
814         }
815 
816     /***
817      * Refresh the node properties.
818      * If the node has stored data, this will trigger a call to the FileStore to refresh the data properties.
819      * Clients should call this method after a data import has completed to update the node properties.
820      * @throws NodeNotFoundException If the node no longer exists in the server database.
821      * @throws FileManagerServiceException If a problem occurs when handling the request. 
822      * @todo Also needs to update list of children ?
823      *
824      */
825     public void refresh()
826         throws NodeNotFoundException, FileManagerServiceException
827         {
828         log.debug("");
829         log.debug("FileManagerDelegateNode.refresh()");
830         try {
831             this.properties = new FileManagerProperties(
832                 delegate.refresh(
833                     this
834                     )
835                 );
836             }
837         catch (FileManagerIdentifierException ouch)
838             {
839             throw new FileManagerServiceException(
840                 "Error in client code, invalid node identifier"
841                 );
842             }
843         }
844 
845     /***
846      * Inner class to provide an iterator on child nodes.
847      *
848      */
849     protected class NodeIteratorImpl
850         implements FileManagerNode.NodeIterator
851         {
852         /***
853          * Our internal iterator of the ivorn list.
854          *
855          */
856         private Iterator iter ;
857 
858         /***
859          * Create an iterator for a list of nodes.
860          *
861          */
862         public NodeIteratorImpl(List list)
863             {
864             log.debug("");
865             log.debug("NodeIteratorImpl.NodeIteratorImpl()");
866             this.iter = list.iterator() ;
867             }
868 
869         /***
870          * Check if the there are more nodes in the iteration.
871          *
872          */
873         public boolean hasNext()
874             {
875             return this.iter.hasNext();
876             }
877 
878         /***
879          * Get the next node in the iteration.
880          * @throws NodeNotFoundException If the node is no longer in the server database (this can happen if another client deletes the node after this iterator was created).
881          * @throws FileManagerServiceException If a problem occurs when handling the request.
882          *
883          */
884         public FileManagerNode next()
885             throws NodeNotFoundException, FileManagerServiceException
886             {
887             log.debug("");
888             log.debug("NodeIteratorImpl.next()");
889             try {
890                 return delegate.getNode(
891                     (Ivorn) this.iter.next()
892                     );
893                 }
894             catch (FileManagerIdentifierException ouch)
895                 {
896                 throw new FileManagerServiceException(
897                     "Unable to parse node ivorn",
898                     ouch
899                     );
900                 }
901             }
902         }
903 
904     /***
905      * Get an iterator for the child nodes of this node.
906      * @throws NodeNotFoundException If this node is no longer in the server database.
907      * @throws FileManagerServiceException If a problem occurs when handling the request.
908      * @throws UnsupportedOperationException If the node does not represent a container.
909      *
910      */
911     public FileManagerNode.NodeIterator iterator()
912         throws NodeNotFoundException, FileManagerServiceException
913         {
914         log.debug("");
915         log.debug("FileManagerDelegateNode.iterator()");
916         try {
917             return new NodeIteratorImpl(
918                 delegate.getChildren(
919                     this.ivorn()
920                     )
921                 );
922             }
923         catch (FileManagerIdentifierException ouch)
924             {
925             throw new FileManagerServiceException(
926                 "Error in client code, invalid node identifier"
927                 );
928             }
929         }
930     }