jafs-library-20020725
[openafs.git] / src / JAVA / classes / org / openafs / jafs / Volume.java
1 /*
2  * @(#)Volume.java      1.0 6/29/2001
3  *
4  * Copyright (c) 2001 International Business Machines Corp.
5  * All rights reserved.
6  *
7  * This software has been released under the terms of the IBM Public
8  * License.  For details, see the LICENSE file in the top-level source
9  * directory or online at http://www.openafs.org/dl/license10.html
10  * 
11  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
12  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
13  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
14  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR
15  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
16  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
17  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
18  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
19  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22  */
23
24 package org.openafs.jafs;
25
26 import java.util.GregorianCalendar;
27 import java.util.Date;
28 import java.io.Serializable;
29
30 /**
31  * An abstract representation of an AFS volume.  It holds information about 
32  * the server, such as what its quota is.
33  * <BR><BR>
34  *
35  * Constructing an instance of a <code>Volume</code> does not mean an actual 
36  * AFS partition is created on a partition -- usually a <code>Volume</code>
37  * object is a representation of an already existing AFS volume.  If, 
38  * however, the <code>Volume</code> is constructed with the name of a 
39  * volume that does not exist in the cell to which the provided 
40  * <code>Partition</code> belongs, a new AFS volume with that name can be
41  * created on that partition by calling the {@link #create(int)} method.  If
42  * such a volume does already exist when this method is called, an exception 
43  * will be thrown.<BR><BR>
44  *
45  * <!--Example of how to use class-->
46  * The following is a simple example of how to construct and use a 
47  * <code>Volume</code> object.  This example obtains the list of 
48  * <code>Volume</code> objects residing on a particular partition, and prints
49  * out the name and id of each one.<BR><BR>
50  *
51  * <PRE>
52  * import org.openafs.jafs.Cell;
53  * import org.openafs.jafs.AFSException;
54  * import org.openafs.jafs.Partition;
55  * import org.openafs.jafs.Server;
56  * import org.openafs.jafs.Volume;
57  * ...
58  * public class ...
59  * {
60  *   ...
61  *   private Cell cell;
62  *   private Server server;
63  *   private Partition partition;
64  *   ...
65  *   public static void main(String[] args) throws Exception
66  *   {
67  *     String username      = arg[0];
68  *     String password      = arg[1];
69  *     String cellName      = arg[2];
70  *     String serverName    = arg[3];
71  *     String partitionName = arg[4];
72  * 
73  *     token  = new Token(username, password, cellName);
74  *     cell   = new Cell(token);
75  *     server = cell.getServer(serverName);
76  *     partition = cell.getPartition(partitionName);
77  * 
78  *     System.out.println("Volumes in Partition " + partition.getName() + ":");
79  *     Volume[] volumes = partition.getVolumes();
80  *     for (int i = 0; i < volumes.length; i++) {
81  *       System.out.println(" -> " + volumes[i] + ": " + volumes[i].getID());
82  *     }
83  *   }
84  *   ...
85  * }
86  * </PRE>
87  *
88  */
89 public class Volume implements Serializable, Comparable
90 {
91   /**
92    * Read-write volume type
93    */
94   public static final int VOLUME_TYPE_READ_WRITE = 0;
95   /**
96    * Read-only volume type
97    */
98   public static final int VOLUME_TYPE_READ_ONLY = 1;
99   /**
100    * Backup volume type
101    */
102   public static final int VOLUME_TYPE_BACKUP = 2;
103
104   /**
105    * Status/disposition ok
106    */
107   public static final int VOLUME_OK = 0;
108   /**
109    * Status/disposition salvage
110    */
111   public static final int VOLUME_SALVAGE = 1;
112   /**
113    * Status/disposition no vnode
114    */
115   public static final int VOLUME_NO_VNODE = 2;
116   /**
117    * Status/disposition no volume
118    */
119   public static final int VOLUME_NO_VOL = 3;
120   /**
121    * Status/disposition volume exists
122    */
123   public static final int VOLUME_VOL_EXISTS = 4;
124   /**
125    * Status/disposition no service 
126    */
127   public static final int VOLUME_NO_SERVICE = 5;
128   /**
129    * Status/disposition offline
130    */
131   public static final int VOLUME_OFFLINE = 6;
132   /**
133    * Status/disposition online
134    */
135   public static final int VOLUME_ONLINE = 7;
136   /**
137    * Status/disposition disk full
138    */
139   public static final int VOLUME_DISK_FULL = 8;
140   /**
141    * Status/disposition over quota
142    */
143   public static final int VOLUME_OVER_QUOTA = 9;
144   /**
145    * Status/disposition busy
146    */
147   public static final int VOLUME_BUSY = 10;
148   /**
149    * Status/disposition moved
150    */
151   public static final int VOLUME_MOVED = 11;
152
153   protected Cell cell;
154   protected Server server;
155   protected Partition partition;
156
157   protected String name;
158
159   protected int id;
160   protected int readWriteID;
161   protected int readOnlyID;
162   protected int backupID;
163
164   protected long creationDate;
165   protected long lastAccessDate;
166   protected long lastUpdateDate;
167   protected long lastBackupDate;
168   protected long copyCreationDate;
169
170   protected int accessesSinceMidnight;
171   protected int fileCount;
172   protected int maxQuota;
173   protected int currentSize;
174   protected int status;
175   protected int disposition;
176   protected int type;
177
178   protected GregorianCalendar creationDateCal;
179   protected GregorianCalendar lastUpdateDateCal;
180   protected GregorianCalendar copyCreationDateCal;
181
182   protected boolean cachedInfo;
183
184   /**
185    * Constructs a new <CODE>Volume</CODE> object instance given the name of 
186    * the AFS volume and the AFS cell, represented by <CODE>partition</CODE>, 
187    * to which it belongs.   This does not actually
188    * create a new AFS volume, it just represents one.
189    * If <code>name</code> is not an actual AFS volume, exceptions
190    * will be thrown during subsequent method invocations on this 
191    * object, unless the {@link #create(int)} method is explicitly called
192    * to create it.
193    *
194    * @param name       the name of the volume to represent 
195    * @param partition  the partition on which the volume resides
196    * @exception AFSException      If an error occurs in the native code
197    */
198   public Volume( String name, Partition partition ) throws AFSException
199   {
200     this.partition = partition;
201     this.server = partition.getServer();
202     this.cell = server.getCell();
203     this.name = name;
204     
205     creationDateCal = null;
206     lastUpdateDateCal = null;
207     copyCreationDateCal = null;
208     
209     id = -1;
210     cachedInfo = false;
211   }
212
213   /**
214    * Constructs a new <CODE>Volume</CODE> object instance given the name of 
215    * the AFS volume and the AFS partition, represented by 
216    * <CODE>partition</CODE>, to which it belongs.    This does not actually
217    * create a new AFS volume, it just represents one.
218    * If <code>name</code> is not an actual AFS volume, exceptions
219    * will be thrown during subsequent method invocations on this 
220    * object, unless the {@link #create(int)} method is explicitly called
221    * to create it.  Note that if the volume doesn't exist and 
222    * <code>preloadAllMembers</code> is true, an exception will be thrown.
223    *
224    * <P> This constructor is ideal for point-in-time representation and 
225    * transient applications. It ensures all data member values are set 
226    * and available without calling back to the filesystem at the first request
227    * for them.  Use the {@link #refresh()} method to address any coherency 
228    * concerns.
229    *
230    * @param name               the name of the volume to represent 
231    * @param partition          the partition on which the volume resides.
232    * @param preloadAllMembers  true will ensure all object members are set 
233    *                           upon construction; otherwise members will be 
234    *                           set upon access, which is the default behavior.
235    * @exception AFSException      If an error occurs in the native code
236    * @see #refresh
237    */
238   public Volume( String name, Partition partition, boolean preloadAllMembers ) 
239       throws AFSException
240   {
241     this(name, partition);
242     if (preloadAllMembers) refresh(true);
243   }
244   
245   /**
246    * Creates a blank <code>Volume</code> given the cell to which the volume
247    * belongs, the server on which the partition resides, and 
248    * the partition on which the volume resides. This blank 
249    * object can then be passed into other methods to fill out its properties. 
250    *
251    * @exception AFSException      If an error occurs in the native code
252    * @param cell       the cell to which the server belongs.
253    * @param server     the server on which the partition resides
254    * @param partition  the partition on which the volume resides
255    */
256   Volume( Partition partition ) throws AFSException
257   {
258     this( null, partition );
259   }
260
261   /*-------------------------------------------------------------------------*/
262
263   /**
264    * Refreshes the properties of this Volume object instance with values from 
265    * the AFS volume it represents.  All properties that have been initialized 
266    * and/or accessed will be renewed according to the values of the AFS volume
267    * this Volume object instance represents.
268    *
269    * <P>Since in most environments administrative changes can be administered
270    * from an AFS command-line program or an alternate GUI application, this
271    * method provides a means to refresh the Java object representation and
272    * thereby ascertain any possible modifications that may have been made
273    * from such alternate administrative programs.  Using this method before
274    * an associated instance accessor will ensure the highest level of 
275    * representative accuracy, accommodating changes made external to the
276    * Java application space.  If administrative changes to the underlying AFS 
277    * system are only allowed via this API, then the use of this method is 
278    * unnecessary.
279    * 
280    * @exception AFSException  If an error occurs in the native code
281    */
282   public void refresh() throws AFSException
283   {
284     refresh(false);
285   }
286
287   /**
288    * Refreshes the properties of this Volume object instance with values from 
289    * the AFS volume it represents.  If <CODE>all</CODE> is <CODE>true</CODE> 
290    * then <U>all</U> of the properties of this Volume object instance will be 
291    * set, or renewed, according to the values of the AFS volume it represents,
292    * disregarding any previously set properties.
293    *
294    * <P> Thus, if <CODE>all</CODE> is <CODE>false</CODE> then properties that 
295    * are currently set will be refreshed and properties that are not set will 
296    * remain uninitialized. See {@link #refresh()} for more information.
297    *
298    * @param all   if true set or renew all object properties; otherwise renew 
299    *              all set properties
300    * @exception AFSException  If an error occurs in the native code
301    * @see #refresh()
302    */
303   protected void refresh(boolean all) throws AFSException
304   {
305     if (all || cachedInfo) refreshInfo();
306   }
307
308   /**
309    * Refreshes the information fields of this <code>Volume</code> to reflect 
310    * the current state of the AFS volume. These include the last update time,
311    * file count, etc.
312    *
313    * @exception AFSException      If an error occurs in the native code
314    */
315   protected void refreshInfo() throws AFSException
316   {
317     getVolumeInfo( cell.getCellHandle(), server.getVosHandle(), 
318                    partition.getID(), getID(), this );
319     cachedInfo = true;
320     creationDateCal = null;
321     lastUpdateDateCal = null;
322     copyCreationDateCal = null;
323   }
324
325   /**
326    * Creates a new volume on the server and partition given upon construction.
327    *
328    * @param quota    the quota for the volume in K, 0 indicates an unlimited 
329    *                 quota
330    *
331    * @exception AFSException  If an error occurs in the native code
332    */ 
333   public void create( int quota ) throws AFSException
334   {
335     id = create( cell.getCellHandle(), server.getVosHandle(), 
336                  partition.getID(), name, quota );
337     maxQuota = quota;
338   }
339
340   /**
341    * Creates a backup volume for this volume.
342    *
343    * @return  the <code>Volume</code> object representation for the
344    *          backup volume that was created
345    * @exception AFSException  If an error occurs in the native code
346    */ 
347   public Volume createBackup( ) throws AFSException
348   {
349     createBackupVolume( cell.getCellHandle(), getID() );
350     return new Volume( name + ".backup", partition );
351   }
352
353   /**
354    * Creates a readonly site for this volume on the specified server and 
355    * partition.  Automatically releases the volume.
356    *
357    * @param sitePartition   the partition on which the readonly volume is 
358    *                        to reside
359    *
360    * @return the <code>Volume</code> representation for the
361    *         read-only volume that was created
362    * @exception AFSException  If an error occurs in the native code
363    */ 
364   public Volume createReadOnly( Partition sitePartition ) 
365       throws AFSException
366   {
367     Server siteServer = sitePartition.getServer();
368     createReadOnlyVolume( cell.getCellHandle(), siteServer.getVosHandle(), 
369                           sitePartition.getID(), getID() );
370     release( false );
371     return new Volume( name + ".readonly", sitePartition );
372   }
373
374   /**
375    * Deletes the volume from the cell.
376    *
377    * @exception AFSException  If an error occurs in the native code
378    */ 
379   public void delete() throws AFSException
380   {
381     delete( cell.getCellHandle(), server.getVosHandle(), partition.getID(), 
382             getID() );
383     name = null;
384     creationDateCal = null;
385     lastUpdateDateCal = null;
386     copyCreationDateCal = null;
387     cell = null;
388     server = null;
389     partition = null;
390   }
391
392   /**
393    * Releases this volume, which updates the read-only copies of it.
394    *
395    * <P> This method will force a complete release; a complete release updates
396    * all read-only sites even if the VLDB entry has a flag.
397    *
398    * @exception AFSException  If an error occurs in the native code
399    */ 
400   public void release() throws AFSException
401   {
402     this.release( true );
403   }
404
405   /**
406    * Releases this volume, which updates the read-only copies of it.
407    *
408    * @param forceComplete   whether or not to force a complete release; 
409    *                        a complete release updates all read-only sites 
410    *                        even if the VLDB entry has a flag
411    * @exception AFSException  If an error occurs in the native code
412    */ 
413   public void release( boolean forceComplete ) throws AFSException
414   {
415     release( cell.getCellHandle(), getID(), forceComplete );
416   }
417
418   /**
419    * Dumps this volume to a file. If you use the dumpSince argument you will 
420    * create an incremental dump, but you can leave it <code>null</code> 
421    * for a full dump.
422    *
423    * @param fileName    the path name of the file on the client machine to 
424    *                    which to dump this volume
425    * @param dumpSince   dump only files that have been modified more recently 
426    *                    than this date
427    * @exception AFSException  If an error occurs in the native code
428    */ 
429   public void dump( String fileName, GregorianCalendar dumpSince ) 
430       throws AFSException
431   {
432     int startTime = 0;
433     if ( dumpSince != null ) {
434       startTime = (int) ((dumpSince.getTime().getTime())/((long) 1000));
435     }
436     dump( cell.getCellHandle(), server.getVosHandle(), partition.getID(), 
437           getID(), startTime, fileName );
438   }
439
440   /**
441    * Dumps this volume to a file. Creates a full dump.
442    *
443    * @param fileName    the path name of the file to which to dump this volume
444    * @exception AFSException  If an error occurs in the native code
445    */ 
446   public void dump( String fileName ) throws AFSException
447   {
448     this.dump( fileName, null );
449   }
450
451   /**
452    * Restores a file to this volume.  Note that this does not have to be an 
453    * existing volume in order to be restored - you may create a 
454    * <code>Volume</code> as a volume that doesn't yet exist and then restore 
455    * a file to it.  Or you can restore over an existing volume.  If a new 
456    * volume is being created with this method, the id will be automatically 
457    * assigned.
458    *
459    * @param fileName    the path name of the file on the client machine from 
460    * which to restore this volume
461    * @param incremental   if true, restores an incremental dump over an 
462    *                      existing volume
463    * @exception AFSException  If an error occurs in the native code
464    */ 
465   public void restore( String fileName, boolean incremental ) 
466       throws AFSException
467   {
468       restore( fileName, incremental, 0 );
469   }
470
471   /**
472    * Restores a file to this volume.  Note that this does not have to be an 
473    * existing volume in order to be restored - you may create a 
474    * <code>Volume</code> as a volume that doesn't yet exist and then restore 
475    * a file to it.  Or you can restore over an existing volume.
476    *
477    * @param fileName    the path name of the file on the client machine from 
478    * which to restore this volume
479    * @param incremental   if true, restores an incremental dump over an 
480    *                      existing volume
481    * @param id     the id to assign this volume
482    * @exception AFSException  If an error occurs in the native code
483    */ 
484   public void restore( String fileName, boolean incremental, int id ) 
485       throws AFSException
486   {
487     restore( cell.getCellHandle(), server.getVosHandle(), partition.getID(), 
488              id, name, fileName, incremental );
489   }
490
491   /**
492    * Mounts this volume, bringing it online and making it accessible.
493    *
494    * @exception AFSException  If an error occurs in the native code
495    */ 
496   public void mount( ) throws AFSException
497   {
498     mount( server.getVosHandle(), partition.getID(), getID(), 0, true );
499   }
500
501   /**
502    * Unmounts this volume, bringing it offline and making it inaccessible.
503    *
504    * @exception AFSException  If an error occurs in the native code
505    */ 
506   public void unmount( ) throws AFSException
507   {
508     unmount( server.getVosHandle(), partition.getID(), getID() );
509   }
510
511   /**
512    * Locks the VLDB enrty for this volume
513    *
514    * @exception AFSException  If an error occurs in the native code
515    */ 
516   public void lock( ) throws AFSException
517   {
518     lock( cell.getCellHandle(), getID() );
519   }
520
521   /**
522    * Unlocks the VLDB entry for this volume
523    *
524    * @exception AFSException  If an error occurs in the native code
525    */ 
526   public void unlock( ) throws AFSException
527   {
528     unlock( cell.getCellHandle(), getID() );
529   }
530
531   /**
532    * Moves this volume to the specified partition (which indirectly 
533    * specifies a new server, as well).  Caution: This will remove any backup 
534    * volumes at the original site.
535    *
536    * @param newPartition   the partition to which to move the volume
537    *
538    * @exception AFSException  If an error occurs in the native code
539    */ 
540   public void moveTo( Partition newPartition ) throws AFSException
541   {
542     Server newServer = newPartition.getServer();
543     move( cell.getCellHandle(), server.getVosHandle(), partition.getID(), 
544           newServer.getVosHandle(), newPartition.getID(), getID() );
545
546     server = newServer;
547     partition = newPartition;
548   }
549
550   /**
551    * Renames this volume.
552    *
553    * @param newName   the new name for this volume
554    * @exception AFSException  If an error occurs in the native code
555    */ 
556   public void rename( String newName ) throws AFSException
557   {
558     rename( cell.getCellHandle(), getID(), newName );
559     name = newName;
560   }
561
562   /**
563    * Salvages (restores consistency to) this volume.  Uses default values for
564    * most salvager options in order to simplify the API.
565    *
566    * @exception AFSException  If an error occurs in the native code
567    */ 
568   public void salvage() throws AFSException
569   {
570     Server.salvage( cell.getCellHandle(), server.getBosHandle(), 
571                     partition.getName(), name, 4, null, null, false, false, 
572                     false, false, false, false );
573   }
574
575   /**
576    * Creates a read-write mount point for this volume.  Does not ensure the 
577    * volume already exists.
578    *
579    * @param directory   the name of the directory where this volume 
580    * should be mounted
581    * @exception AFSException  If an error occurs in the native code
582    */
583   public void createMountPoint( String directory ) throws AFSException
584   {
585     createMountPoint(directory, true); 
586   }
587
588   /**
589    * Creates a mount point for this volume.  Does not ensure the volume 
590    * already exists.
591    *
592    * @param directory   the name of the directory where this volume should be 
593    *                    mounted
594    * @param readWrite   whether or not this mount point should be read-write
595    * @exception AFSException  If an error occurs in the native code
596    */
597   public void createMountPoint( String directory, boolean readWrite ) 
598     throws AFSException
599   {
600     Cell.createMountPoint( cell.getCellHandle(), directory, getName(), 
601                            readWrite, false ); 
602   }
603
604   //////////////// accessors:  ////////////////////////
605
606   /**
607    * Returns the name of this volume.
608    *
609    * @return the name of this volume
610    */
611   public String getName()
612   {
613     return name;
614   }
615
616   /**
617    * Returns this volume's hosting partition.
618    *
619    * @return this volume's partition
620    */
621   public Partition getPartition()
622   {
623     return partition;
624   }
625
626   /**
627    * Returns the id of this volume.   
628    *
629    * @exception AFSException  If an error occurs in the native code
630    * @return the id of this volume
631    */
632   public int getID() throws AFSException
633   {
634     if( id == -1 && name != null ) {
635         String nameNoSuffix;
636         if( name.endsWith( "backup" ) ) {
637             type = VOLUME_TYPE_BACKUP;
638             nameNoSuffix = name.substring( 0, name.lastIndexOf( '.' ) );
639         } else if( name.endsWith( "readonly" ) ) {
640             type = VOLUME_TYPE_READ_ONLY;
641             nameNoSuffix = name.substring( 0, name.lastIndexOf( '.' ) );
642         } else {
643             type = VOLUME_TYPE_READ_WRITE;
644             nameNoSuffix = name;
645         }
646         id = translateNameToID( cell.getCellHandle(), 
647                                      nameNoSuffix, type );
648     }
649     return id;
650   }
651
652   /**
653    * Returns the read-write ID of this volume
654    *
655    * @exception AFSException  If an error occurs in the native code
656    * @return the read-write id
657    */
658   public int getReadWriteID() throws AFSException
659   {
660     if( !cachedInfo ) {
661       refreshInfo();
662     }
663     return readWriteID;
664   }
665
666   /**
667    * Returns the read-only ID of this volume
668    *
669    * @exception AFSException  If an error occurs in the native code
670    * @return the read-only id
671    */
672   public int getReadOnlyID() throws AFSException
673   {
674     if( !cachedInfo ) {
675       refreshInfo();
676     }
677     return readOnlyID;
678   }
679
680   /**
681    * Returns the backup ID of this volume
682    *
683    * @exception AFSException  If an error occurs in the native code
684    * @return the backup id
685    */
686   public int getBackupID() throws AFSException
687   {
688     if( !cachedInfo ) {
689       refreshInfo();
690     }
691     return backupID;
692   }
693
694   /**
695    * Returns the date the volume was created
696    *
697    * @return the date the volume was created
698    * @exception AFSException  If an error occurs in the native code
699    */
700   public GregorianCalendar getCreationDate() throws AFSException
701   {
702     if( !cachedInfo ) {
703       refreshInfo();
704     }
705     if( creationDateCal == null ) {
706       // make it into a date . . .
707       creationDateCal = new GregorianCalendar();
708       Date d = new Date( creationDate*1000 );
709       creationDateCal.setTime( d );
710     }
711     return creationDateCal;
712   }
713
714   /**
715    * Returns the date the volume was last updated.
716    * After this method is called once, it saves the date 
717    * and returns that date on subsequent calls, 
718    * until the {@link #refresh()} method is called and a more current 
719    * value is obtained.
720    *
721    * @return the date the volume was last updated
722    * @exception AFSException  If an error occurs in the native code
723    */
724   public GregorianCalendar getLastUpdateDate() throws AFSException
725   {
726     if( !cachedInfo ) {
727       refreshInfo();
728     }
729     if( lastUpdateDateCal == null ) {
730       // make it into a date . . .
731       lastUpdateDateCal = new GregorianCalendar();
732       Date d = new Date( lastUpdateDate*1000 );
733       lastUpdateDateCal.setTime( d );
734     }
735     return lastUpdateDateCal;
736   }
737
738   /**
739    * Returns the date the volume was copied.
740    * After this method is called once, it saves the date 
741    * and returns that date on subsequent calls, 
742    * until the {@link #refresh()} method is called and a more current 
743    * value is obtained.
744    *
745    * @return the date the volume was copied
746    * @exception AFSException  If an error occurs in the native code
747    */
748   public GregorianCalendar getCopyCreationDate() throws AFSException
749   {
750     if( !cachedInfo ) {
751       refreshInfo();
752     }
753     if( copyCreationDateCal == null ) {
754       // make it into a date . . .
755       copyCreationDateCal = new GregorianCalendar();
756       Date d = new Date( copyCreationDate*1000 );
757       copyCreationDateCal.setTime( d );
758     }
759     return copyCreationDateCal;
760   }
761
762   /**
763    * Returns the number of accesses since midnight.
764    * After this method is called once, it saves the value 
765    * and returns that value on subsequent calls, 
766    * until the {@link #refresh()} method is called and a more current 
767    * value is obtained.
768    *
769    * @exception AFSException  If an error occurs in the native code
770    * @return the number of accesses since midnight
771    */
772   public int getAccessesSinceMidnight() throws AFSException
773   {
774     if( !cachedInfo ) {
775           refreshInfo();
776     }
777     return accessesSinceMidnight;
778   }
779
780   /**
781    * Returns file count.
782    * After this method is called once, it saves the value 
783    * and returns that value on subsequent calls, 
784    * until the {@link #refresh()} method is called and a more current 
785    * value is obtained.
786    *
787    * @exception AFSException  If an error occurs in the native code
788    * @return the file count
789    */
790   public int getFileCount() throws AFSException
791   {
792     if( !cachedInfo ) {
793           refreshInfo();
794     }
795     return fileCount;
796   }
797
798   /**
799    * Returns current volume size in K.
800    * After this method is called once, it saves the value 
801    * and returns that value on subsequent calls, 
802    * until the {@link #refresh()} method is called and a more current 
803    * value is obtained.
804    *
805    * @exception AFSException  If an error occurs in the native code
806    * @return the current volume size in K
807    */
808   public int getCurrentSize() throws AFSException
809   {
810     if( !cachedInfo ) refreshInfo();
811     return currentSize;
812   }
813
814   /**
815    * Returns the difference between quota and current volume size (in K).
816    *
817    * <P> Please note: the product of this method is <U>not</U> saved.
818    *
819    * @exception AFSException  If an error occurs in the native code
820    * @return the current free space in K
821    */
822   public int getTotalFreeSpace() throws AFSException
823   {
824     if ( !cachedInfo ) refreshInfo();
825     return (maxQuota - currentSize);
826   }
827
828   /**
829    * Returns this volume's quota, expressed in kilobyte blocks (1024 
830    * kilobyte blocks equal one megabyte). After this method is called once, 
831    * it saves the value and returns that value on subsequent calls, 
832    * until the {@link #refresh()} method is called and a more current 
833    * value is obtained.
834    *
835    * <P><B>Note:</B> A quota value of zero, "0", grants an unlimited quota
836    * in AFS.  Consequently, to avoid delusion this method will throw an 
837    * {@link AFSException} if the returning value is zero.
838    *
839    * @exception AFSException  If an error occurs in the native code or
840    *                               this volume's quota is configured as
841    *                               unlimited.
842    * @return the volume quota in K
843    * @see #isQuotaUnlimited()
844    */
845   public int getQuota() throws AFSException
846   {
847     if ( !cachedInfo ) refreshInfo();
848     if (maxQuota == 0) {
849       throw new AFSException("Volume with id " + id + 
850                                   " has an unlimited quota configured.", 0);
851     }
852     return maxQuota;
853   }
854
855   /**
856    * Tests whether this volume's quota is configured as unlimited.
857    *
858    * <P>After this method is called once, it saves the value and returns 
859    * that value on subsequent calls, until the {@link #refresh()} 
860    * method is called and a more current value is obtained.
861    *
862    * @exception AFSException  If an error occurs in the native code
863    * @return <CODE>true</CODE> if this volume's quota is configured as
864    *         unlimited; otherwise <CODE>false</CODE>.
865    * @see #getQuota()
866    */
867   public boolean isQuotaUnlimited() throws AFSException
868   {
869     if ( !cachedInfo ) refreshInfo();
870     return (maxQuota == 0);
871   }
872
873   /**
874    * Returns volume status. Possible values are:<ul>
875    *       <li>{@link #VOLUME_OK}</li>
876    *       <li>{@link #VOLUME_SALVAGE}</li>
877    *       <li>{@link #VOLUME_NO_VNODE}</li>
878    *       <li>{@link #VOLUME_NO_VOL}</li>
879    *       <li>{@link #VOLUME_VOL_EXISTS}</li>
880    *       <li>{@link #VOLUME_NO_SERVICE}</li>
881    *       <li>{@link #VOLUME_OFFLINE}</li>
882    *       <li>{@link #VOLUME_ONLINE}</li>
883    *       <li>{@link #VOLUME_DISK_FULL}</li>
884    *       <li>{@link #VOLUME_OVER_QUOTA}</li>
885    *       <li>{@link #VOLUME_BUSY}</li>
886    *       <li>{@link #VOLUME_MOVED}</li></ul>
887    * Typical value is VOLUME_OK.
888    * After this method is called once, it saves the value 
889    * and returns that value on subsequent calls, 
890    * until the {@link #refresh()} method is called and a more current 
891    * value is obtained.
892    *
893    * @exception AFSException  If an error occurs in the native code
894    * @return volume status
895    */
896   public int getStatus() throws AFSException
897   {
898     if( !cachedInfo ) refreshInfo();
899     return status;
900   }
901
902   /**
903    * Returns volume disposition. Possible values are:<ul>
904    *       <li>{@link #VOLUME_OK}</li>
905    *       <li>{@link #VOLUME_SALVAGE}</li>
906    *       <li>{@link #VOLUME_NO_VNODE}</li>
907    *       <li>{@link #VOLUME_NO_VOL}</li>
908    *       <li>{@link #VOLUME_VOL_EXISTS}</li>
909    *       <li>{@link #VOLUME_NO_SERVICE}</li>
910    *       <li>{@link #VOLUME_OFFLINE}</li>
911    *       <li>{@link #VOLUME_ONLINE}</li>
912    *       <li>{@link #VOLUME_DISK_FULL}</li>
913    *       <li>{@link #VOLUME_OVER_QUOTA}</li>
914    *       <li>{@link #VOLUME_BUSY}</li>
915    *       <li>{@link #VOLUME_MOVED}</li></ul>
916    * Typical value is VOLUME_ONLINE.
917    * After this method is called once, it saves the value 
918    * and returns that value on subsequent calls, 
919    * until the {@link #refresh()} method is called and a more current 
920    * value is obtained.
921    *
922    * @exception AFSException  If an error occurs in the native code
923    * @return volume disposition
924    */
925   public int getDisposition() throws AFSException
926   {
927     if( !cachedInfo ) refreshInfo();
928     return disposition;
929   }
930
931   /**
932    * Returns volume type. Possible values are:<ul>
933    *       <li>{@link #VOLUME_TYPE_READ_WRITE}</li>
934    *       <li>{@link #VOLUME_TYPE_READ_ONLY}</li>
935    *       <li>{@link #VOLUME_TYPE_BACKUP}</li></ul>
936    *
937    * @exception AFSException  If an error occurs in the native code
938    * @return volume type
939    */
940   public int getType() throws AFSException
941   {
942     if( !cachedInfo ) refreshInfo();
943     return type;
944   }
945
946   //////////////// mutators:  ////////////////////////
947
948   /**
949    * Sets quota of volume, 0 denotes an unlimited quota.
950    *
951    * @exception AFSException  If an error occurs in the native code
952    * @param quota  the new volume quota in K (0 for unlimited)
953    */
954   public void setQuota( int quota ) throws AFSException
955   {
956     this.changeQuota( cell.getCellHandle(), server.getVosHandle(), 
957                       partition.getID(), getID(), quota );
958     maxQuota = quota;
959   }
960
961   /////////////// custom information methods ////////////////////
962
963   /**
964    * Returns a <code>String</code> representation of this <code>Volume</code>.
965    * Contains the information fields.
966    *
967    * @return a <code>String</code> representation of the <code>Volume</code>
968    */
969   protected String getInfo()
970   {
971       String r;
972       try {
973         r = "Volume: " + name + "\tid: " + getID() + "\n";
974         
975         r += "\tread-write id: " + getReadWriteID() + "\tread-only id: " 
976           + getReadOnlyID() + "\n";
977         r += "\tbackup id: " + getBackupID() + "\n";
978
979         r += "\tcreation date: " + getCreationDate().getTime() + "\n";
980         r += "\tlast update date: " + getLastUpdateDate().getTime() + "\n";
981         r += "\tcopy creation date: " + getCopyCreationDate().getTime() + "\n";
982         r += "\taccesses since midnight: " + getAccessesSinceMidnight() + "\n";
983         r += "\tfile count: " + getFileCount() + "\n";
984         r += "\tcurrent size: " + getCurrentSize() + " K\tquota: " + 
985           getQuota() + " K\n";
986         r += "\tstatus: ";
987         switch( getStatus() ) {
988         case VOLUME_OK: 
989             r += "OK";
990             break;
991         default:
992             r += "OTHER";
993         }
994
995         r += "\tdisposition: ";
996         switch( getDisposition() ) {
997         case VOLUME_ONLINE: 
998             r += "ONLINE";
999             break;
1000         default:
1001             r += "OTHER - " + getDisposition();
1002         }
1003         r += "\n";
1004
1005         r += "\ttype: ";
1006         switch( getType() ) {
1007         case VOLUME_TYPE_READ_WRITE: 
1008             r += "read-write";
1009             break;
1010         case VOLUME_TYPE_READ_ONLY: 
1011             r += "read-only";
1012             break;
1013         case VOLUME_TYPE_BACKUP: 
1014             r += "backup";
1015             break;
1016         default:
1017             r += "OTHER";
1018         }
1019         r += "\n";
1020
1021       } catch( Exception e ) {
1022         return e.toString();
1023       }
1024       return r;
1025   }
1026
1027   /////////////// custom override methods ////////////////////
1028
1029   /**
1030    * Compares two Volume objects respective to their names and does not
1031    * factor any other attribute.    Alphabetic case is significant in 
1032    * comparing names.
1033    *
1034    * @param     volume    The Volume object to be compared to this Volume 
1035    *                      instance
1036    * 
1037    * @return    Zero if the argument is equal to this Volume's name, a
1038    *            value less than zero if this Volume's name is
1039    *            lexicographically less than the argument, or a value greater
1040    *            than zero if this Volume's name is lexicographically
1041    *            greater than the argument
1042    */
1043   public int compareTo(Volume volume)
1044   {
1045     return this.getName().compareTo(volume.getName());
1046   }
1047
1048   /**
1049    * Comparable interface method.
1050    *
1051    * @see #compareTo(Volume)
1052    */
1053   public int compareTo(Object obj)
1054   {
1055     return compareTo((Volume)obj);
1056   }
1057
1058   /**
1059    * Tests whether two <code>Volume</code> objects are equal, based on their 
1060    * names and hosting partition.
1061    *
1062    * @param otherVolume   the Volume to test
1063    * @return whether the specifed Volume is the same as this Volume
1064    */
1065   public boolean equals( Volume otherVolume )
1066   {
1067     return ( name.equals(otherVolume.getName()) ) &&
1068            ( this.getPartition().equals(otherVolume.getPartition()) );
1069   }
1070
1071   /**
1072    * Returns the name of this <CODE>Volume</CODE>
1073    *
1074    * @return the name of this <CODE>Volume</CODE>
1075    */
1076   public String toString()
1077   {
1078     return getName();
1079   }
1080
1081
1082   /////////////// native methods ////////////////////
1083
1084   /**
1085    * Fills in the information fields of the provided <code>Volume</code>.
1086    *
1087    * @param cellHandle    the handle of the cell to which the volume belongs
1088    * @see Cell#getCellHandle
1089    * @param serverHandle  the vos handle of the server on which the volume 
1090    *                      resides
1091    * @see Server#getVosServerHandle
1092    * @param partition   the numeric id of the partition on which the volume 
1093    *                    resides
1094    * @param volId  the numeric id of the volume for which to get the info
1095    * @param theVolume   the {@link Volume Volume} object in which to fill in 
1096    *                    the information
1097    * @exception AFSException   If an error occurs in the native code
1098    */
1099   protected static native void getVolumeInfo( int cellHandle, int serverHandle,
1100                                               int partition, int volId, 
1101                                               Volume theVolume ) 
1102         throws AFSException;
1103
1104   /**
1105    * Creates a volume on a particular partition.
1106    *
1107    * @param cellHandle    the handle of the cell in which to create the volume
1108    * @see Cell#getCellHandle
1109    * @param serverHandle  the vos handle of the server on which to create 
1110    *                      the volume
1111    * @see Server#getVosServerHandle
1112    * @param partition   the numeric id of the partition on which to create 
1113    *                    the volume
1114    * @param volumeName   the name of the volume to create
1115    * @param quota    the amount of space (in KB) to set as this volume's quota
1116    * @return the numeric ID assigned to the volume
1117    * @exception AFSException   If an error occurs in the native code
1118    */
1119   protected static native int create( int cellHandle, int serverHandle, 
1120                                       int partition, String volumeName, 
1121                                       int quota ) 
1122         throws AFSException;
1123
1124   /**
1125    * Deletes a volume from a particular partition.
1126    *
1127    * @param cellHandle    the handle of the cell in which to delete the volume
1128    * @see Cell#getCellHandle
1129    * @param serverHandle  the vos handle of the server from which to delete 
1130    *                      the volume
1131    * @see Server#getVosServerHandle
1132    * @param partition   the numeric id of the partition from which to delete 
1133    *                    the volume
1134    * @param volId   the numeric id of the volume to delete
1135    * @exception AFSException   If an error occurs in the native code
1136    */
1137   protected static native void delete( int cellHandle, int serverHandle, 
1138                                        int partition, int volId ) 
1139         throws AFSException;
1140
1141   /**
1142    * Creates a backup volume for the specified regular volume.
1143    *
1144    * @param cellHandle    the handle of the cell to which the volume belongs
1145    * @param volId  the numeric id of the volume for which to create a backup 
1146    *               volume
1147    * @see Cell#getCellHandle
1148    */
1149   protected static native void createBackupVolume( int cellHandle, int volId )
1150         throws AFSException;
1151
1152   /**
1153    * Creates a read-only volume for the specified regular volume.
1154    *
1155    * @param cellHandle    the handle of the cell to which the volume belongs
1156    * @param serverHandle  the vos handle of the server on which the read-only 
1157    *                      volume is to reside 
1158    * @see Server#getVosServerHandle
1159    * @param partition   the numeric id of the partition on which the read-only 
1160                         volume is to reside 
1161    * @param volId  the numeric id of the volume for which to create a read-only volume
1162    * @see Cell#getCellHandle
1163    */
1164   protected static native void createReadOnlyVolume( int cellHandle, 
1165                                                      int serverHandle, 
1166                                                      int partition, int volId )
1167         throws AFSException;
1168
1169   /**
1170    * Deletes a read-only volume for the specified regular volume.
1171    *
1172    * @param cellHandle    the handle of the cell to which the volume belongs
1173    * @param serverHandle  the vos handle of the server on which the read-only 
1174    *                      volume residea 
1175    * @see Server#getVosServerHandle
1176    * @param partition   the numeric id of the partition on which the read-only
1177    *                     volume resides 
1178    * @param volId  the numeric read-write id of the volume for which to 
1179    *               delete the read-only volume
1180    * @see Cell#getCellHandle
1181    */
1182   protected static native void deleteReadOnlyVolume( int cellHandle, 
1183                                                      int serverHandle, 
1184                                                      int partition, int volId )
1185         throws AFSException;
1186
1187   /**
1188    * Changes the quota of the specified volume.
1189    *
1190    * @param cellHandle    the handle of the cell to which the volume belongs
1191    * @see Cell#getCellHandle
1192    * @param serverHandle  the vos handle of the server on which the volume 
1193    *                      resides
1194    * @see Server#getVosServerHandle
1195    * @param partition   the numeric id of the partition on which the volume 
1196    *                    resides
1197    * @param volId  the numeric id of the volume for which to change the quota
1198    * @param newQuota    the new quota (in KB) to assign the volume
1199    * @exception AFSException   If an error occurs in the native code
1200    */
1201   protected static native void changeQuota( int cellHandle, int serverHandle, 
1202                                             int partition, int volId, 
1203                                             int newQuota ) 
1204         throws AFSException;
1205
1206   /**
1207    * Move the specified volume to a different site.
1208    *
1209    * @param cellHandle    the handle of the cell to which the volume belongs
1210    * @see Cell#getCellHandle
1211    * @param fromServerHandle  the vos handle of the server on which the volume
1212    *                          currently resides
1213    * @see Server#getVosServerHandle
1214    * @param fromPartition   the numeric id of the partition on which the volume
1215    *                        currently resides
1216    * @param toServerHandle  the vos handle of the server to which the volume 
1217    *                        should be moved
1218    * @param toPartition   the numeric id of the partition to which the volume 
1219    *                      should be moved
1220    * @param volId  the numeric id of the volume to move
1221    * @exception AFSException   If an error occurs in the native code
1222    */
1223   protected static native void move( int cellHandle, int fromServerHandle, 
1224                                      int fromPartition, int toServerHandle, 
1225                                      int toPartition, int volId ) 
1226         throws AFSException;
1227
1228   /**
1229    * Releases the specified volume that has readonly volume sites.
1230    *
1231    * @param cellHandle    the handle of the cell to which the volume belongs
1232    * @param volId  the numeric id of the volume to release
1233    * @param forceComplete  whether or not to force a complete release
1234    * @see Cell#getCellHandle
1235    */
1236   protected static native void release( int cellHandle, int volId, 
1237                                         boolean forceComplete )
1238         throws AFSException;
1239
1240   /**
1241    * Dumps the specified volume to a file.
1242    *
1243    * @param cellHandle    the handle of the cell to which the volume belongs
1244    * @see Cell#getCellHandle
1245    * @param serverHandle  the vos handle of the server on which the volume 
1246    *                      resides
1247    * @see Server#getVosServerHandle
1248    * @param partition   the numeric id of the partition on which the 
1249    *                    volume resides
1250    * @param volId  the numeric id of the volume to dump
1251    * @param startTime   files with a modification time >= to this time will 
1252    *                    be dumped
1253    * @param dumpFile   the full path of the file to which to dump
1254    * @exception AFSException   If an error occurs in the native code
1255    */
1256   protected static native void dump( int cellHandle, int serverHandle, 
1257                                      int partition, int volId, int startTime, 
1258                                      String dumpFile ) 
1259         throws AFSException;
1260
1261   /**
1262    * Restores the specified volume from a dump file.
1263    *
1264    * @param cellHandle    the handle of the cell to which the volume belongs
1265    * @see Cell#getCellHandle
1266    * @param serverHandle  the vos handle of the server on which the volume is 
1267    *                      to reside
1268    * @see Server#getVosServerHandle
1269    * @param partition   the numeric id of the partition on which the volume is
1270    *                    to reside
1271    * @param volId  the numeric id to assign the restored volume (can be 0)
1272    * @param volumeName  the name of the volume to restore as
1273    * @param dumpFile   the full path of the dump file from which to restore
1274    * @param incremental  if true, restores an incremental dump over an existing
1275    *                     volume (server and partition values must correctly 
1276    *                     indicate the current position of the existing volume),
1277    *                     otherwise restores a full dump
1278    * @exception AFSException   If an error occurs in the native code
1279    */
1280   protected static native void restore( int cellHandle, int serverHandle, 
1281                                         int partition, int volId, 
1282                                         String volumeName, String dumpFile, 
1283                                         boolean incremental ) 
1284         throws AFSException;
1285
1286   /**
1287    * Renames the specified read-write volume.
1288    *
1289    * @param cellHandle    the handle of the cell to which the volume belongs
1290    * @see Cell#getCellHandle
1291    * @param volId  the numeric id of the read-write volume to rename
1292    * @param newVolumeName  the new name for the volume
1293    * @exception AFSException   If an error occurs in the native code
1294    */
1295   protected static native void rename( int cellHandle, int volId, 
1296                                        String newVolumeName ) 
1297         throws AFSException;
1298
1299   /**
1300    * "Mounts" the specified volume, bringing it online.
1301    *
1302    * @param serverHandle  the vos handle of the server on which the volume 
1303    *                      resides
1304    * @see Server#getVosServerHandle
1305    * @param partition   the numeric id of the partition on which the volume 
1306    *                    resides
1307    * @param volId  the numeric id of the volume to bring online
1308    * @param sleepTime  ?  (not sure what this is yet, possibly a time to wait 
1309    *                      before brining it online)
1310    * @param offline   ?  (not sure what this is either, probably the current 
1311    *                     status of the volume -- busy or offline)
1312    * @exception AFSException   If an error occurs in the native code
1313    */
1314   protected static native void mount( int serverHandle, int partition, 
1315                                       int volId, int sleepTime, 
1316                                       boolean offline ) 
1317         throws AFSException;
1318
1319   /**
1320    * "Unmounts" the specified volume, bringing it offline.
1321    *
1322    * @param serverHandle  the vos handle of the server on which the volume 
1323    *                      resides
1324    * @see Server#getVosServerHandle
1325    * @param partition   the numeric id of the partition on which the volume 
1326    *                    resides
1327    * @param volId  the numeric id of the volume to bring offline
1328    * @exception AFSException   If an error occurs in the native code
1329    */
1330   protected static native void unmount( int serverHandle, int partition, 
1331                                         int volId ) 
1332         throws AFSException;
1333
1334   /**
1335    * Locks the VLDB entry specified volume
1336    *
1337    * @param cellHandle  the handle of the cell on which the volume resides
1338    * @see Cell#getCellHandle
1339    * @param volId  the numeric id of the volume to lock
1340    * @exception AFSException   If an error occurs in the native code
1341    */
1342   protected static native void lock( int cellHandle, int volId ) 
1343         throws AFSException;
1344
1345   /**
1346    * Unlocks the VLDB entry of the specified volume
1347    *
1348    * @param cellHandle  the handle of the cell on which the volume resides
1349    * @see Cell#getCellHandle
1350    * @param volId  the numeric id of the volume to unlock
1351    * @exception AFSException   If an error occurs in the native code
1352    */
1353   protected static native void unlock( int cellHandle, int volId ) 
1354         throws AFSException;
1355
1356   /**
1357    * Translates a volume name into a volume id
1358    *
1359    * @param cellHandle    the handle of the cell to which the volume belongs
1360    * @see Cell#getCellHandle
1361    * @param name  the name of the volume in question, cannot end in backup or
1362    *              readonly
1363    * @param type  the type of volume: read-write, read-only, or backup.  
1364    *              Acceptable values are:<ul>
1365    *              <li>{@link #VOLUME_TYPE_READ_WRITE}</li>
1366    *              <li>{@link #VOLUME_TYPE_READ_ONLY}</li>
1367    *              <li>{@link #VOLUME_TYPE_BACKUP}</li></ul> 
1368    * @return   the id of the volume in question
1369    * @exception AFSException  If an error occurs in the native code
1370    */
1371   protected static native int translateNameToID( int cellHandle, String name, 
1372                                                  int volumeType )
1373     throws AFSException;
1374
1375   /**
1376    * Reclaims all memory being saved by the volume portion of the native 
1377    * library. This method should be called when no more <code>Volume</code> 
1378    * objects are expected to be used.
1379    */
1380   protected static native void reclaimVolumeMemory();
1381 }
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394