jafs-library-20020725
[openafs.git] / src / JAVA / classes / org / openafs / jafs / Server.java
1 /*
2  * @(#)Server.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.io.Serializable;
27 import java.text.DecimalFormat;
28 import java.util.ArrayList;
29 import java.util.Calendar;
30 import java.util.GregorianCalendar;
31
32 /**
33  * An abstract representation of an AFS server.  It holds information about 
34  * the server, such as what its processes are.
35  * <BR><BR>
36  *
37  * Constructing an instance of a <code>Server</code> does not mean an actual 
38  * AFS server is created and added to a cell -- on the contrary, a 
39  * <code>Server</code> object must be a representation of an already existing 
40  * AFS server.  There is no way to create a new AFS server through this API.  
41  * See <a href="http://www.openafs.org">OpenAFS.org</a> for information on how
42  * to create a new AFS server.<BR><BR>
43  *
44  * A <code>Server</code> object may represent either an AFS file server,
45  * an AFS database server, or both if the same machine serves both
46  * purposes.<BR><BR>
47  *
48  * Each <code>Server</code> object has its own individual set of
49  * <code>Partition</code>s, <code>Process</code>es, and <code>Key</code>s.
50  * This represents the properties and attributes of an actual AFS server.
51  * <BR><BR>
52  *    
53  * <!--Example of how to use class-->
54  * The following is a simple example of how to construct and use a Server 
55  * object.  This example constructs a <code>Server</code> using the 
56  * <code>Cell</code> representing teh AFS cell to which the server belongs, 
57  * and prints out the names of all the partitions residing on the server.
58  * <BR><BR>
59  *
60  * <PRE>
61  * import org.openafs.jafs.Cell;
62  * import org.openafs.jafs.AFSException;
63  * import org.openafs.jafs.Partition;
64  * import org.openafs.jafs.Server;
65  * ...
66  * public class ...
67  * {
68  *   ...
69  *   private Cell cell;
70  *   private Server server;
71  *   ...
72  *   public static void main(String[] args) throws Exception
73  *   {
74  *     String username   = arg[0];
75  *     String password   = arg[1];
76  *     String cellName   = arg[2];
77  *     String serverName = arg[3];
78  * 
79  *     token = new Token(username, password, cellName);
80  *     cell   = new Cell(token);
81  *     server = new Server(serverName, cell);
82  * 
83  *     System.out.println("Partitions in Server " + server.getName() + ":");
84  *     if( server.isFileServer() ) {
85  *       Partition[] partitions = server.getPartitions();
86  *       for (int i = 0; i < partitions.length; i++) {
87  *         System.out.println(" -> " + partitions[i]);
88  *       }
89  *     }
90  *   }
91  *   ...
92  * }
93  * </PRE>
94  *
95  */
96 public class Server implements Serializable, Comparable
97 {
98   /**
99    * Used for binary restart time types.
100    */
101   private static final int RESTART_BINARY = 0;
102
103   /**
104    * Used for general restart time types.
105    */
106   private static final int RESTART_GENERAL = 1;
107
108   protected String name;
109   protected Cell cell;
110
111   protected int vosHandle;
112   protected int bosHandle;
113
114   protected boolean database;
115   protected boolean fileServer;
116
117   // these will be true if the machine is supposedly listed as a server 
118   // but that's wrong, or the machine is down 
119   protected boolean badFileServer;  
120   protected boolean badDatabase;
121
122   // String IP Address of address[0]
123   protected String[] ipAddresses;
124
125   protected ArrayList partitionNames;
126   protected ArrayList partitions;
127   protected ArrayList adminNames;
128   protected ArrayList admins;
129   protected ArrayList keys;
130   protected ArrayList processNames;
131   protected ArrayList processes;
132
133   // Storage information
134   protected int totalSpace;
135   protected int totalQuota;
136   protected int totalFreeSpace;
137   protected int totalUsedSpace;
138
139   protected ExecutableTime genRestartTime;
140   protected ExecutableTime binRestartTime;
141
142   protected boolean cachedInfo;
143
144   /**
145    * Constructs a new <CODE>Server</CODE> object instance given the 
146    * name of the AFS server and the AFS cell, represented by 
147    * <CODE>cell</CODE>, to which it belongs.  This does not actually
148    * create a new AFS server, it just represents an existing one.
149    * If <code>name</code> is not an actual AFS server, exceptions
150    * will be thrown during subsequent method invocations on this 
151    * object.
152    *
153    * @param name  the name of the server to represent
154    * @param cell  the cell to which the server belongs.
155    * @exception AFSException      If an error occurs in the native code
156    */
157   public Server( String name, Cell cell ) throws AFSException
158   {
159     this.name = name;
160     this.cell = cell;
161     
162     cachedInfo = false;
163
164     vosHandle = 0;
165     bosHandle = 0;
166
167     ipAddresses = new String[16];
168
169     partitionNames = null;
170     partitions = null;
171     adminNames = null;
172     admins = null;
173     keys = null;
174     processNames = null;
175     processes = null;
176   }
177
178   /**
179    * Constructs a new <CODE>Server</CODE> object instance given the name 
180    * of the AFS server and the AFS cell, represented by <CODE>cell</CODE>, 
181    * to which it belongs.   This does not actually
182    * create a new AFS server, it just represents an existing one.
183    * If <code>name</code> is not an actual AFS server, exceptions
184    * will be thrown during subsequent method invocations on this 
185    * object.
186    *
187    * <P> This constructor is ideal for point-in-time representation and 
188    * transient applications.  It ensures all data member values are set 
189    * and available without calling back to the filesystem at the first 
190    * request for them.  Use the {@link #refresh()} method to address any 
191    * coherency concerns.
192    *
193    * @param name               the name of the server to represent 
194    * @param cell               the cell to which the server belongs.
195    * @param preloadAllMembers  true will ensure all object members are 
196    *                           set upon construction;
197    *                           otherwise members will be set upon access, 
198    *                           which is the default behavior.
199    * @exception AFSException      If an error occurs in the native code
200    * @see #refresh
201    */
202   public Server( String name, Cell cell, boolean preloadAllMembers ) 
203       throws AFSException
204   {
205     this(name, cell);
206     if (preloadAllMembers) refresh(true);
207   }
208   
209   /**
210    * Constructs a blank <code>Server</code> object instance given the cell to 
211    * which the server belongs.  This blank object can then be passed into 
212    * other methods to fill out its properties.
213    *
214    * @param cell       the cell to which the server belongs.
215    * @exception AFSException      If an error occurs in the native code
216    */
217   Server( Cell cell ) throws AFSException
218   {
219     this( null, cell );
220   }
221
222   /*-------------------------------------------------------------------------*/
223
224   /**
225    * Refreshes the properties of this Server object instance with values 
226    * from the AFS server it represents.  All properties that have been 
227    * initialized and/or accessed will be renewed according to the values 
228    * of the AFS server this Server object instance represents.
229    *
230    * <P>Since in most environments administrative changes can be administered
231    * from an AFS command-line program or an alternate GUI application, this
232    * method provides a means to refresh the Java object representation and
233    * thereby ascertain any possible modifications that may have been made
234    * from such alternate administrative programs.  Using this method before
235    * an associated instance accessor will ensure the highest level of 
236    * representative accuracy, accommodating changes made external to the
237    * Java application space.  If administrative changes to the underlying AFS 
238    * system are only allowed via this API, then the use of this method is 
239    * unnecessary.
240    * 
241    * @exception AFSException  If an error occurs in the native code
242    */
243   public void refresh() throws AFSException
244   {
245     refresh(false);
246   }
247
248   /**
249    * Refreshes the properties of this Server object instance with values 
250    * from the AFS server it represents.  If <CODE>all</CODE> is 
251    * <CODE>true</CODE> then <U>all</U> of the properties of this Server 
252    * object instance will be set, or renewed, according to the values of the 
253    * AFS server it represents, disregarding any previously set properties.
254    *
255    * <P> Thus, if <CODE>all</CODE> is <CODE>false</CODE> then properties that 
256    * are currently set will be refreshed and properties that are not set 
257    * will remain uninitialized.
258    * See {@link #refresh()} for more information.
259    *
260    * @param all   if true set or renew all object properties; 
261    *              otherwise renew all set properties
262    * @exception AFSException  If an error occurs in the native code
263    * @see #refresh()
264    */
265   protected void refresh(boolean all) throws AFSException
266   {
267     if ( all ) {
268       refreshProcesses();
269       refreshProcessNames();
270       refreshKeys();
271       refreshAdminNames();
272       refreshAdmins();
273       refreshPartitionNames();
274       refreshPartitions(all);
275       refreshInfo();
276       refreshGeneralRestart();
277       refreshBinaryRestart();
278     } else {
279       if ( processes      != null ) refreshProcesses();
280       if ( processNames   != null ) refreshProcessNames();
281       if ( keys           != null ) refreshKeys();
282       if ( adminNames     != null ) refreshAdminNames();
283       if ( admins         != null ) refreshAdmins();
284       if ( partitionNames != null ) refreshPartitionNames();
285       if ( partitions     != null ) refreshPartitions(all);
286       if ( genRestartTime != null ) refreshGeneralRestart();
287       if ( binRestartTime != null ) refreshBinaryRestart();
288       if ( cachedInfo )             refreshInfo();
289     }
290   }
291
292   /**
293    * Refreshes the information fields of this <code>Server</code> to 
294    * reflect the current state of the AFS server.  These fields include
295    * the IP addresses and the fileserver types.
296    *
297    * @exception AFSException      If an error occurs in the native code
298    */
299   protected void refreshInfo() throws AFSException
300   {
301     getServerInfo( cell.getCellHandle(), name, this );
302     cachedInfo = true;
303   }
304
305   /**
306    * Refreshes the general restart time fields of this <code>Server</code> 
307    * to reflect the current state of the AFS server.
308    *
309    * @exception AFSException      If an error occurs in the native code
310    */
311   protected void refreshGeneralRestart() throws AFSException
312   {
313     if (genRestartTime == null) genRestartTime = new ExecutableTime();
314     getRestartTime( getBosHandle(), RESTART_GENERAL, genRestartTime );
315   }
316
317   /**
318    * Refreshes the binary restart time fields of this <code>Server</code> 
319    * to reflect the current state of the AFS server.
320    *
321    * @exception AFSException      If an error occurs in the native code
322    */
323   protected void refreshBinaryRestart() throws AFSException
324   {
325     if (binRestartTime == null) binRestartTime = new ExecutableTime();
326     getRestartTime( getBosHandle(), RESTART_BINARY, binRestartTime );
327   }
328
329   /**
330    * Obtains the most current list of <code>Partition</code> objects 
331    * of this server.
332    *
333    * @exception AFSException  If an error occurs in the native code
334    */
335   protected void refreshPartitions() throws AFSException
336   {
337     this.refreshPartitions(false);
338   }
339
340   /**
341    * Obtains the most current list of <code>Partition</code> objects of 
342    * this server.
343    *
344    * @param refreshVolumes force all volumes contained in each 
345    *                       partition to be refreshed.
346    *
347    * @exception AFSException  If an error occurs in the native code
348    */
349   protected void refreshPartitions(boolean refreshVolumes) 
350       throws AFSException
351   {
352     if (!isFileServer() || isBadFileServer()) return;
353
354     Partition currPartition;
355
356     int iterationID = getPartitionsBegin( cell.getCellHandle(), 
357                                           getVosHandle() );
358     
359     partitions = new ArrayList();
360     
361     currPartition = new Partition( this );
362     while( getPartitionsNext( iterationID, currPartition ) != 0 ) {
363       //Only volumes are necessary since volume information 
364       //is populated at time of construction
365       if (refreshVolumes) currPartition.refreshVolumes();
366       partitions.add( currPartition );
367       currPartition = new Partition( this );
368     } 
369     getPartitionsDone( iterationID );
370     totalSpace = 0;
371     totalQuota = 0;
372     totalUsedSpace = 0;
373     totalFreeSpace = 0;
374   }
375
376   /**
377    * Obtains the most current list of partition names of this server.
378    *
379    * @exception AFSException  If an error occurs in the native code
380    */
381   protected void refreshPartitionNames() throws AFSException
382   {
383     if (!isFileServer() || isBadFileServer()) return;
384
385     String currName;
386
387     int iterationID = getPartitionsBegin( cell.getCellHandle(), 
388                                           getVosHandle() );
389     
390     partitionNames = new ArrayList();
391     
392     while( ( currName = getPartitionsNextString( iterationID ) ) != null ) {
393         partitionNames.add( currName );
394     } 
395     getPartitionsDone( iterationID );
396   }
397
398   /**
399    * Obtains the most current list of bos admin names of this server.
400    *
401    * @exception AFSException  If an error occurs in the native code
402    */
403   protected void refreshAdminNames() throws AFSException
404   {
405     String currName;
406
407     int iterationID = getBosAdminsBegin( getBosHandle() );
408     
409     adminNames = new ArrayList();
410     
411     while( ( currName = getBosAdminsNextString( iterationID ) ) != null ) {
412         adminNames.add( currName );
413     } 
414     getBosAdminsDone( iterationID );
415   }
416
417   /**
418    * Obtains the most current list of admin <code>User</code> objects of 
419    * this server.
420    *
421    * @exception AFSException  If an error occurs in the native code
422    */
423   protected void refreshAdmins() throws AFSException
424   {
425     User currUser;
426
427     int iterationID = getBosAdminsBegin( getBosHandle() );
428         
429     admins = new ArrayList();
430         
431     currUser = new User( cell );
432     while( getBosAdminsNext( cell.getCellHandle(), iterationID, currUser ) 
433            != 0 ) {
434       admins.add( currUser );
435       currUser = new User( cell );
436     } 
437     getBosAdminsDone( iterationID );
438   }
439
440   /**
441    * Obtains the most current list of <code>Key</code> objects of this server.
442    *
443    * @exception AFSException  If an error occurs in the native code
444    */
445   protected void refreshKeys() throws AFSException
446   {
447     Key currKey;
448
449     int iterationID = getKeysBegin( getBosHandle() );
450     
451     keys = new ArrayList();
452     
453     currKey = new Key( this );
454     while( getKeysNext( iterationID, currKey ) != 0 ) {
455         keys.add( currKey );
456         currKey = new Key( this );
457     } 
458     getKeysDone( iterationID );
459   }
460
461   /**
462    * Obtains the most current list of process names of this server.
463    *
464    * @exception AFSException  If an error occurs in the native code
465    */
466   protected void refreshProcessNames() throws AFSException
467   {
468     String currName;
469
470     int iterationID = getProcessesBegin( getBosHandle() );
471     
472     processNames = new ArrayList();
473     
474     while( ( currName = getProcessesNextString( iterationID ) ) != null ) {
475         processNames.add( currName );
476     } 
477     getProcessesDone( iterationID );
478   }
479
480   /**
481    * Obtains the most current list of <code>Process</code> objects of 
482    * this server.
483    *
484    * @exception AFSException  If an error occurs in the native code
485    */
486   protected void refreshProcesses() throws AFSException
487   {
488     Process currProcess;
489
490     int iterationID = getProcessesBegin( getBosHandle() );
491     
492     processes = new ArrayList();
493     
494     currProcess = new Process( this );
495     while( getProcessesNext( getBosHandle(), iterationID, currProcess ) 
496            != 0 ) {
497         processes.add( currProcess );
498         currProcess = new Process( this );
499     } 
500     getProcessesDone( iterationID );
501   }
502
503   /**
504    * Add a bos admin to the UserList file of this server, in order to
505    * given the AFS user represented by <code>admin</code> full bos
506    * administrative privileges on this server.
507    *
508    * @param admin   the admin to add
509    * @exception AFSException  If an error occurs in the native code
510    */
511   public void addAdmin( User admin ) throws AFSException
512   {
513     String adminName = admin.getName();
514     
515     addBosAdmin( getBosHandle(), adminName );
516     if ( adminNames != null ) {
517         adminNames.add( adminName );
518     }
519   }
520
521   /**
522    * Remove a bos admin from the UserList file of this server, in order to
523    * take away from the AFS user represented by <code>admin</code> bos
524    * administrative privileges on this machine.
525    *
526    * @param admin   the admin to remove
527    * @exception AFSException  If an error occurs in the native code
528    */
529   public void removeAdmin( User admin ) throws AFSException
530   {
531     String adminName = admin.getName();
532     
533     removeBosAdmin( getBosHandle(), adminName );
534     if ( adminNames != null ) {
535         adminNames.remove( adminNames.indexOf( adminName ) );
536         adminNames.trimToSize();
537     }
538   }
539
540   /**
541    * Syncs this server to the VLDB.
542    *
543    * @exception AFSException  If an error occurs in the native code
544    */
545   public void syncServer() throws AFSException
546   {
547     syncServerWithVLDB( cell.getCellHandle(), getVosHandle(), -1 );
548   }
549
550   /**
551    * Syncs the VLDB to this server.
552    *
553    * @exception AFSException  If an error occurs in the native code
554    */
555   public void syncVLDB() throws AFSException
556   {
557     syncVLDBWithServer( cell.getCellHandle(), getVosHandle(), -1, false );
558   }
559
560   /**
561    * Salvages (restores consistency to) this server. Uses default values for
562    * most salvager options in order to simplify the API.
563    *
564    * @exception AFSException  If an error occurs in the native code
565    */ 
566   public void salvage() throws AFSException
567   {
568     salvage( cell.getCellHandle(), getBosHandle(), null, null, 4, null, null, 
569              false, false, false, false, false, false );
570   }
571
572   /**
573    * Starts up all bos processes on this server.
574    *
575    * @exception AFSException  If an error occurs in the native code
576    */
577   public void startAllProcesses() throws AFSException
578   {
579     startAllProcesses( getBosHandle() );
580   }
581
582   /**
583    * Stops all bos processes on this server.
584    *
585    * @exception AFSException  If an error occurs in the native code
586    */
587   public void stopAllProcesses() throws AFSException
588   {
589     stopAllProcesses( getBosHandle() );
590   }
591
592   /**
593    * Restarts all bos processes on this server.
594    *
595    * @exception AFSException  If an error occurs in the native code
596    */
597   public void restartAllProcesses() throws AFSException
598   {
599     restartAllProcesses( getBosHandle(), false );
600   }
601
602   /**
603    * Restarts bos server and all bos processes on this server.
604    *
605    * @exception AFSException  If an error occurs in the native code
606    */
607   public void restartBosServer() throws AFSException
608   {
609     restartAllProcesses( getBosHandle(), true );
610   }
611
612   /**
613    * Gets the contents of a log file, in one large <code>String</code>.  
614    * The log cannot be in AFS file space.
615    *
616    * @return a <code>String</code> containing the contents of the log file
617    * @exception AFSException  If an error occurs in the native code
618    */
619   public String getLog( String logLocation ) throws AFSException
620   {
621     return getLog( getBosHandle(), logLocation );
622   }
623
624   /**
625    * Unauthenticates all server-related tokens that have been obtained by 
626    * this <code>Server</code> object, and shuts this server object down.
627    * This method should only be called when this <code>Server</code> or any 
628    * of the objects constructed using this <code>Server</code> will not be 
629    * used anymore.  Note that this does not effect the actual AFS server;
630    * it merely closes the representation.
631    *
632    * @exception AFSException  If an error occurs in the native code
633    */
634   public void close() throws AFSException
635   {
636     if ( vosHandle != 0 ) {
637         closeVosServerHandle( vosHandle );
638     }
639     if ( bosHandle != 0 ) {
640         closeBosServerHandle( bosHandle );
641     }
642
643     cachedInfo = false;
644
645     vosHandle = 0;
646     bosHandle = 0;
647
648     partitionNames = null;
649     partitions = null;
650     adminNames = null;
651     admins = null;
652     keys = null;
653     processNames = null;
654     processes = null;
655   }
656
657   //////////////// accessors:  ////////////////////////
658
659   /**
660    * Returns the name of this server.
661    *
662    * @return the name of this server
663    */
664   public String getName()
665   {
666     return name;
667   }
668
669   /**
670    * Returns the <code>Cell</code> object with which this <code>Server</code>
671    * was constructed.  It represents the actual AFS cell to which this
672    * server belongs.
673    *
674    * @return this server's cell
675    */
676   public Cell getCell()
677   {
678     return cell;
679   }
680
681   /**
682    * Returns the number of BOS administrators assigned to this server.
683    *
684    * <P>If the total list of admins or admin names have already been 
685    * collected (see {@link #getAdmins()}), then the returning value will
686    * be calculated based upon the current list.  Otherwise, AFS will be
687    * explicitly queried for the information.
688    *
689    * <P> The product of this method is not saved, and is recalculated
690    * with every call.
691    *
692    * @return the number of admins on this server.
693    * @exception AFSException  If an error occurs 
694    *                               in any of the associated native methods
695    * @see #getAdmins()
696    * @see #getAdminNames()
697    */
698   public int getAdminCount() throws AFSException
699   {
700     if (adminNames != null) {
701       return adminNames.size();
702     } else if (admins != null) {
703       return admins.size();
704     } else {
705       return getBosAdminCount(getBosHandle());
706     }
707   }
708
709   /**
710    * Retrieves an array containing all of the admin <code>User</code> objects 
711    * associated with this <code>Server</code>, each of which are an abstract 
712    * representation of an actual bos administrator of the AFS server.  
713    * After this method is called once, it saves the array of 
714    * <code>User</code>s and returns that saved array on subsequent calls, 
715    * until the {@link #refresh()} method is called and a more current list 
716    * is obtained.
717    *
718    * @return a <code>User</code> array of the admins of the server.
719    * @exception AFSException  If an error occurs in the native code
720    * @see #refresh()
721    */
722   public User[] getAdmins() throws AFSException
723   {
724     if ( admins == null ) refreshAdmins();
725     return (User[]) admins.toArray( new User[admins.size()] );
726   }
727
728   /**
729    * Retrieves an array containing all of the names of bos admins 
730    * associated with this <code>Server</code>. After this method
731    * is called once, it saves the array of <code>String</code>s and returns
732    * that saved array on subsequent calls, until the {@link #refresh()} method
733    * is called and a more current list is obtained.
734    *
735    * @return a <code>String</code> array of the bos admin of the server.
736    * @exception AFSException  If an error occurs in the native code
737    * @see #refresh()
738    */
739   public String[] getAdminNames() throws AFSException
740   {
741     if ( adminNames == null ) refreshAdminNames();
742     return (String []) adminNames.toArray( new String[adminNames.size()] );
743   }
744
745   /**
746    * Returns the number of partitions on this server.
747    *
748    * <P>If the total list of partitions or partition names have already been 
749    * collected (see {@link #getPartitions()}), then the returning value will
750    * be calculated based upon the current list.  Otherwise, AFS will be
751    * explicitly queried for the information.
752    *
753    * <P> The product of this method is not saved, and is recalculated
754    * with every call.
755    *
756    * @return the number of partitions on this server.
757    * @exception AFSException  If an error occurs 
758    *                               in any of the associated native methods
759    * @see #getPartitions()
760    * @see #getPartitionNames()
761    */
762   public int getPartitionCount() throws AFSException
763   {
764     if (partitionNames != null) {
765       return partitionNames.size();
766     } else if (partitions != null) {
767       return partitions.size();
768     } else {
769       return getPartitionCount(cell.getCellHandle(), getVosHandle());
770     }
771   }
772
773   /**
774    * Retrieves the <CODE>Partition</CODE> object (which is an abstract 
775    * representation of an actual AFS partition of this server) designated 
776    * by <code>name</code> (i.e. "/vicepa", etc.).  If a partition by 
777    * that name does not actually exist in AFS on the server
778    * represented by this object, an {@link AFSException} will be
779    * thrown.
780    *
781    * @param name the name of the partition to retrieve
782    * @return <CODE>Partition</CODE> designated by <code>name</code>.
783    * @exception AFSException  If an error occurs in the native code
784    * @exception NullPointerException  If <CODE>name</CODE> is 
785    *                                  <CODE>null</CODE>.
786    */
787   public Partition getPartition(String name) throws AFSException
788   {
789     if (name == null) throw new NullPointerException();
790     if (isFileServer() && !isBadFileServer()) {
791       Partition partition = new Partition(name, this);
792       partition.refresh(true);
793       return partition;
794     } else {
795       //Throw "No such entry" error
796       throw new AFSException("Server is not a file server.", 363524);
797     }
798   }
799
800   /**
801    * Retrieves an array containing all of the <code>Partition</code> objects 
802    * associated with this <code>Server</code>, each of which are an abstract 
803    * representation of an actual AFS partition of the AFS server.  
804    * After this method is called once, it saves the array of 
805    * <code>Partition</code>s and returns that saved array on subsequent calls, 
806    * until the {@link #refresh()} method is called and a more current list 
807    * is obtained.
808    *
809    * @return a <code>Partition</code> array of the <code>Partition</code> 
810    *         objects of the server.
811    * @exception AFSException  If an error occurs in the native code
812    * @see #refresh()
813    */
814   public Partition[] getPartitions() throws AFSException
815   {
816     if ( partitions == null ) refreshPartitions();
817     return (Partition []) 
818         partitions.toArray( new Partition[partitions.size()] );
819   }
820
821   /**
822    * Retrieves an array containing all of the names of partitions
823    * associated with this <code>Server</code> (i.e. "vicepa", etc.). 
824    * After this method is called once, it saves the array of 
825    * <code>String</code>s and returns that saved array on subsequent calls, 
826    * until the {@link #refresh()} method is called and a more current 
827    * list is obtained.
828    *
829    * @return a <code>String</code> array of the partitions of the server.
830    * @exception AFSException  If an error occurs in the native code
831    * @see #refresh()
832    */
833   public String[] getPartitionNames() throws AFSException
834   {
835     if ( partitionNames == null ) refreshPartitionNames();
836     return (String []) 
837         partitionNames.toArray( new String[partitionNames.size()] );
838   }
839
840   /**
841    * Retrieves the <CODE>Key</CODE> object (which is an abstract 
842    * representation of an actual AFS partition of this server) designated 
843    * by <code>nkeyVersion</code>.  If a key with 
844    * that version does not actually exist in AFS on the server
845    * represented by this object, <code>null</code> is returned.
846    *
847    * @param keyVersion the version of the key to retrieve
848    * @return <CODE>Key</CODE> designated by <code>keyVersion</code>.
849    * @exception AFSException  If an error occurs in the native code
850    */
851   public Key getKey(int keyVersion) throws AFSException
852   {
853     try {
854       Key[] keys = this.getKeys();
855       for (int i = 0; i < keys.length; i++) {
856         if (keys[i].getVersion() == keyVersion) {
857           return keys[i];
858         }
859       }
860     } catch (Exception e) {
861       e.printStackTrace();
862     }
863     return null;
864   }
865
866   /**
867    * Returns the number of keys on this server.
868    *
869    * <P>If the total list of keys has already been 
870    * collected (see {@link #getKeys()}), then the returning value will
871    * be calculated based upon the current list.  Otherwise, AFS will be
872    * explicitly queried for the information.
873    *
874    * <P> The product of this method is not saved, and is recalculated
875    * with every call.
876    *
877    * @return the number of keys on this server.
878    * @exception AFSException  If an error occurs 
879    *                               in any of the associated native methods
880    * @see #getKeys()
881    */
882   public int getKeyCount() throws AFSException
883   {
884     if (keys != null) {
885       return keys.size();
886     } else {
887       return getKeyCount(getBosHandle());
888     }
889   }
890
891   /**
892    * Retrieves an array containing all of the <code>Key</code> objects 
893    * associated with this <code>Server</code>, each of which are an abstract 
894    * representation of an actual AFS key of the AFS server.  
895    * After this method is called once, it saves the array of 
896    * <code>Key</code>s and returns that saved array on subsequent calls, 
897    * until the {@link #refresh()} method is called and a more current list 
898    * is obtained.
899    *
900    * @return a <code>Key</code> array of the <code>Key</code> objects 
901    *         of the server.
902    * @exception AFSException  If an error occurs in the native code
903    * @see #refresh()
904    */
905   public Key[] getKeys() throws AFSException
906   {
907     if ( keys == null ) refreshKeys();
908     return (Key[]) keys.toArray( new Key[keys.size()] );
909   }
910
911   /**
912    * Retrieves the <CODE>Process</CODE> object (which is an abstract 
913    * representation of an actual AFS process of this server) designated 
914    * by <code>name</code> (i.e. "kaserver", etc.).  If a process by 
915    * that name does not actually exist in AFS on the server
916    * represented by this object, an {@link AFSException} will be
917    * thrown.
918    *
919    * @param name the name of the process to retrieve
920    * @return <CODE>Process</CODE> designated by <code>name</code>.
921    * @exception AFSException  If an error occurs in the native code
922    * @exception NullPointerException  If <CODE>name</CODE> is 
923    *                                  <CODE>null</CODE>.
924    */
925   public Process getProcess(String name) throws AFSException
926   {
927     if (name == null) throw new NullPointerException();
928     //if (isFileServer() && !isBadFileServer()) {
929       Process process = new Process(name, this);
930       process.refresh(true);
931       return process;
932     //}
933   }
934
935   /**
936    * Returns the number of processes hosted by this server.
937    *
938    * <P>If the total list of processes or process names have already been 
939    * collected (see {@link #getProcesses()}), then the returning value will
940    * be calculated based upon the current list.  Otherwise, AFS will be
941    * explicitly queried for the information.
942    *
943    * <P> The product of this method is not saved, and is recalculated
944    * with every call.
945    *
946    * @return the number of processes on this server.
947    * @exception AFSException  If an error occurs 
948    *                               in any of the associated native methods
949    * @see #getProcesses()
950    * @see #getProcessNames()
951    */
952   public int getProcessCount() throws AFSException
953   {
954     if (processNames != null) {
955       return processNames.size();
956     } else if (processes != null) {
957       return processes.size();
958     } else {
959       return getProcessCount(getBosHandle());
960     }
961   }
962
963   /**
964    * Retrieves an array containing all of the <code>Process</code> objects 
965    * associated with this <code>Server</code>, each of which are an abstract 
966    * representation of an actual AFS process of the AFS server.  
967    * After this method is called once, it saves the array of 
968    * <code>Process</code>es and returns that saved array on subsequent calls, 
969    * until the {@link #refresh()} method is called and a more current list 
970    * is obtained.
971    *
972    * @return a <code>Process</code> array of the <code>Process</code> 
973    *         objects of the server.
974    * @exception AFSException  If an error occurs in the native code
975    * @see #refresh()
976    */
977   public Process[] getProcesses() throws AFSException
978   {
979     if ( processes == null ) refreshProcesses();
980     return (Process[]) processes.toArray( new Process[processes.size()] );
981   }
982
983   /**
984    * Retrieves an array containing all of the names of processes
985    * associated with this <code>Server</code> (i.e. "kaserver", etc.). 
986    * After this method is called once, it saves the array of 
987    * <code>String</code>s and returns that saved array on subsequent calls, 
988    * until the {@link #refresh()} method is called and a more current 
989    * list is obtained.
990    *
991    * @return a <code>String</code> array of the processes of the server.
992    * @exception AFSException  If an error occurs in the native code
993    * @see #refresh()
994    */
995   public String[] getProcessNames() throws AFSException
996   {
997     if ( processNames == null ) refreshProcessNames();
998     return (String[]) processNames.toArray( new String[processNames.size()] );
999   }
1000
1001   /**
1002    * Returns whether or not this server is a database machine, meaning it runs
1003    * processes such as the "kaserver" and "vlserver", and participates in 
1004    * elections.
1005    *
1006    * @return whether or not this user this server is a database machine.
1007    * @exception AFSException  If an error occurs in the native code
1008    * @see #refresh()
1009    */
1010   public boolean isDatabase() throws AFSException
1011   {
1012     if (!cachedInfo) refreshInfo();
1013     return database;
1014   }
1015
1016   /**
1017    * Returns whether or not this server is a file server machine, meaning it
1018    * runs the "fs" process and stores AFS volumes.
1019    *
1020    * @return whether or not this user this server is a file server machine.
1021    * @exception AFSException  If an error occurs in the native code
1022    * @see #refresh()
1023    */
1024   public boolean isFileServer() throws AFSException
1025   {
1026     if (!cachedInfo) refreshInfo();
1027     return fileServer;
1028   }
1029
1030   /**
1031    * Returns whether or not this server is a database machine AND 
1032    * either it isn't in reality (e.g. it's incorrectly configured) 
1033    * or it's currently down.
1034    *
1035    * @return whether or not this server is a database machine 
1036    *         AND either it isn't in reality or it's currently down
1037    * @exception AFSException  If an error occurs in the native code
1038    * @see #refresh()
1039    */
1040   public boolean isBadDatabase() throws AFSException
1041   {
1042     if (!cachedInfo) refreshInfo();
1043     return badDatabase;
1044   }
1045
1046   /**
1047    * Returns whether this machine thinks it's a file server AND 
1048    * either it isn't in reality (e.g. it's incorrectly configured) 
1049    * or it's currently down.
1050    *
1051    * @return whether or not this server is a file server machine AND 
1052    *         either it isn't in reality or it's currently down
1053    * @exception AFSException  If an error occurs in the native code
1054    * @see #refresh()
1055    */
1056   public boolean isBadFileServer() throws AFSException
1057   {
1058     if (!cachedInfo) refreshInfo();
1059     return badFileServer;
1060   }
1061
1062   /**
1063    * Returns this server's IP address as a String.  It returns it in 
1064    * dotted quad notation (i.e. 123.123.123.123).  
1065    *
1066    * @return this server's IP address as a String
1067    * @exception AFSException  If an error occurs in the native code
1068    * @see #refresh()
1069    */
1070   public String[] getIPAddresses() throws AFSException
1071   {
1072     if (!cachedInfo) refreshInfo();
1073     int n = 16;
1074     for (int i = 0; i < n; i++) {
1075       if (ipAddresses[i] == null) {
1076         n = i;
1077         break;
1078       }
1079     }
1080     String[] addresses = new String[n];
1081     System.arraycopy(ipAddresses, 0, addresses, 0, n);
1082     return addresses;
1083   }
1084
1085   /**
1086    * Returns the BOS Server's general restart time in the form of an
1087    * ExecutableTime object.  This is the time at which the bos server
1088    * restarts itself and all running processes.  After this method
1089    * is called once, it saves the time and returns
1090    * that value on subsequent calls, until the {@link #refresh()} method
1091    * is called and a more current value is obtained.
1092    *
1093    * @return the general restart time
1094    * @exception AFSException  If an error occurs in the native code
1095    * @see Server.ExecutableTime
1096    * @see #refresh()
1097    */
1098   public ExecutableTime getGeneralRestartTime() throws AFSException
1099   {
1100     if (genRestartTime == null) refreshGeneralRestart();
1101     return genRestartTime;
1102   }
1103
1104   /**
1105    * Returns the BOS Server's binary restart time in the form of an
1106    * ExecutableTime object.  This is the time at which all new or newly
1107    * modified AFS binaries are restarted.  After this method
1108    * is called once, it saves the time and returns
1109    * that value on subsequent calls, until the {@link #refresh()} method
1110    * is called and a more current value is obtained.
1111    *
1112    * @return the binary restart time
1113    * @exception AFSException  If an error occurs in the native code
1114    * @see Server.ExecutableTime
1115    * @see #refresh()
1116    */
1117   public ExecutableTime getBinaryRestartTime() throws AFSException
1118   {
1119     if (binRestartTime == null) refreshBinaryRestart();
1120     return binRestartTime;
1121   }
1122
1123   /**
1124    * Returns the total space on this server (a sum of the space of all the 
1125    * partitions associated with this server).  If this server is not a 
1126    * file server, zero will be returned. After this method
1127    * is called once, it saves the total space and returns
1128    * that value on subsequent calls, until the {@link #refresh()} method
1129    * is called and a more current value is obtained.
1130    *
1131    * @return the total space on this server
1132    * @exception AFSException  If an error occurs in the native code
1133    * @see #refresh()
1134    */
1135   public int getTotalSpace() throws AFSException
1136   {
1137     if (partitions == null) refreshPartitions(true);
1138     if (!isFileServer() || isBadFileServer()) return 0;
1139     if (totalSpace == 0) {
1140       Partition[] partitions = getPartitions();
1141       for (int i = 0; i < partitions.length; i++) {
1142         totalSpace += partitions[i].getTotalSpace();
1143       }
1144     }
1145     return totalSpace;
1146   }
1147
1148   /**
1149    * Returns the total free space on this server (a sum of the free space of 
1150    * all the partitions associated with this server).  If this server is not a 
1151    * file server, zero will be returned. After this method
1152    * is called once, it saves the total free space and returns
1153    * that value on subsequent calls, until the {@link #refresh()} method
1154    * is called and a more current value is obtained.
1155    *
1156    * @return the total free space on this server
1157    * @exception AFSException  If an error occurs in the native code
1158    * @see #refresh()
1159    */
1160   public int getTotalFreeSpace() throws AFSException
1161   {
1162     if (partitions == null) refreshPartitions(true);
1163     if (!isFileServer() || isBadFileServer()) return 0;
1164     if (totalFreeSpace == 0) {
1165       Partition[] partitions = getPartitions();
1166       for (int i = 0; i < partitions.length; i++) {
1167         totalFreeSpace += partitions[i].getTotalFreeSpace();
1168       }
1169     }
1170     return totalFreeSpace;
1171   }
1172
1173   /**
1174    * Returns the total used space on this server (a sum of the used space of 
1175    * all the partitions associated with this server).  If this server is not a 
1176    * file server, zero will be returned. After this method
1177    * is called once, it saves the total used space and returns
1178    * that value on subsequent calls, until the {@link #refresh()} method
1179    * is called and a more current value is obtained.
1180    *
1181    * @return the total space on this partition
1182    * @exception AFSException  If an error occurs in the native code
1183    * @see #getTotalSpace()
1184    * @see #getTotalFreeSpace()
1185    */
1186   public int getTotalUsedSpace() throws AFSException
1187   {
1188     if (totalUsedSpace == 0) {
1189       totalUsedSpace = getTotalSpace() - getTotalFreeSpace();
1190     }
1191     return totalUsedSpace;
1192   }
1193
1194   /**
1195    * Returns this server's vos handle.
1196    *
1197    * @return this server's vos handle
1198    * @exception AFSException  If an error occurs in the native code
1199    */
1200   protected int getVosHandle() throws AFSException
1201   {
1202     if ( vosHandle == 0 ) {
1203       vosHandle = getVosServerHandle( cell.getCellHandle(), name );
1204     }
1205     return vosHandle;
1206   }
1207
1208   /**
1209    * Returns this server's bos handle.
1210    *
1211    * @return this server's bos handle
1212    * @exception AFSException  If an error occurs in the native code
1213    */
1214   protected int getBosHandle() throws AFSException
1215   {
1216     if ( bosHandle == 0 ) {
1217       bosHandle = getBosServerHandle( cell.getCellHandle(), name );
1218     }
1219     return bosHandle;
1220   }
1221
1222   //////////////// mutators:  ////////////////////////
1223
1224   /**
1225    * Sets the BOS general restart time.   This is the time at which the bos 
1226    * server restarts itself and all running processes.
1227    *
1228    * @param executableTime  Executable time object that represents what 
1229    * the BOS Server's general restart time should be. 
1230    * @exception AFSException  If an error occurs in the native code
1231    * @see Server.ExecutableTime
1232    */
1233   public void setGeneralRestartTime( ExecutableTime executableTime ) 
1234       throws AFSException
1235   {
1236     this.setRestartTime( getBosHandle(), RESTART_GENERAL, executableTime );
1237   }
1238
1239   /**
1240    * Sets the BOS binary restart time.   This is the time at which all new 
1241    * or newly modified AFS binaries are restarted.
1242    *
1243    * @param executableTime  Executable time object that represents what 
1244    *                        the BOS Server's binary restart time should be.
1245    * @exception AFSException  If an error occurs in the native code
1246    * @see Server.ExecutableTime
1247    */
1248   public void setBinaryRestartTime( ExecutableTime executableTime ) 
1249       throws AFSException
1250   {
1251     this.setRestartTime( getBosHandle(), RESTART_BINARY, executableTime );
1252   }
1253
1254   /////////////// custom information methods ////////////////////
1255
1256   /**
1257    * Returns a <code>String</code> representation of this <code>Server</code>.
1258    * Contains the information fields and a list of partitions, admin, and 
1259    * processes.
1260    *
1261    * @return a <code>String</code> representation of the <code>Server</code>
1262    */
1263   protected String getInfo()
1264   {
1265     String r;
1266     try {
1267     
1268     r = "Server: " + name + "\n";
1269
1270     r += "\tdatabase: " + isDatabase() + "\t\tfileServer: " + 
1271         isFileServer() + "\n";
1272     r += "\tbad database: " + isBadDatabase() + "\tbad fileServer: " + 
1273         isBadFileServer() + "\n";
1274     //r += "\tAddress: " + getIPAddress()[0] + "\n";
1275
1276     // restart times:
1277     r += "\tGeneral restart date: " + getGeneralRestartTime() + "\n";
1278     r += "\tBinary restart date: " + getBinaryRestartTime() + "\n";
1279     
1280     if ( isFileServer() && !isBadFileServer() ) {
1281       r += "\tPartitions:\n";
1282       
1283       String parts[] = getPartitionNames();
1284       
1285       for( int i = 0; i < parts.length; i++ ) {
1286         r += "\t\t" + parts[i] + "\n";
1287       }
1288     }
1289
1290     if ( (isDatabase() && !isBadDatabase()) || 
1291          (isFileServer() && !isBadFileServer()) ) {
1292         r += "\tAdmins:\n";
1293         
1294         String ads[] = getAdminNames();
1295     
1296         for( int i = 0; i < ads.length; i++ ) {
1297         r += "\t\t" + ads[i] + "\n";
1298         }
1299     }
1300
1301     if ( (isDatabase() && !isBadDatabase()) || 
1302          (isFileServer() && !isBadFileServer()) ) {
1303         r += "\tProcesses:\n";
1304         
1305         String pros[] = getProcessNames();
1306     
1307         for( int i = 0; i < pros.length; i++ ) {
1308         r += "\t\t" + pros[i] + "\n";
1309         }
1310     }
1311
1312     } catch( Exception e ) {
1313     return e.toString();
1314     }
1315     return r;
1316   }
1317
1318   /**
1319    * Returns a <code>String</code> containing the <code>String</code> 
1320    * representations of all the partitions of this <code>Server</code>.
1321    *
1322    * @return    a <code>String</code> representation of the partitions
1323    * @see       Partition#getInfo
1324    */
1325   protected String getInfoPartitions() throws AFSException
1326   {
1327     String r;
1328     r = "Server: " + name + "\n\n";
1329     r += "--Partitions--\n";
1330
1331     Partition parts[] = getPartitions();
1332
1333     for( int i = 0; i < parts.length; i++ ) {
1334         r += parts[i].getInfo() + "\n";
1335     }
1336     return r;
1337   }
1338
1339   /**
1340    * Returns a <code>String</code> containing the <code>String</code> 
1341    * representations of all the keys of this <code>Server</code>.
1342    *
1343    * @return    a <code>String</code> representation of the keys
1344    * @see       Key#getInfo
1345    */
1346   protected String getInfoKeys() throws AFSException
1347   {
1348     String r;
1349
1350     r = "Server: " + name + "\n\n";
1351     r += "--Keys--\n";
1352
1353     Key kys[] = getKeys();
1354
1355     for( int i = 0; i < kys.length; i++ ) {
1356         r += kys[i].getInfo() + "\n";
1357     }
1358
1359     return r;
1360   }
1361
1362   /**
1363    * Returns a <code>String</code> containing the <code>String</code> 
1364    * representations of all the processes of this <code>Server</code>.
1365    *
1366    * @return    a <code>String</code> representation of the processes
1367    * @see       Process#getInfo
1368    */
1369   protected String getInfoProcesses() throws AFSException
1370   {
1371     String r;
1372
1373     r = "Server: " + name + "\n\n";
1374     r += "--Processes--\n";
1375
1376     Process pros[] = getProcesses();
1377
1378     for( int i = 0; i < pros.length; i++ ) {
1379         r += pros[i].getInfo() + "\n";
1380     }
1381     return r;
1382   }
1383
1384   /////////////// custom override methods ////////////////////
1385
1386   /**
1387    * Compares two Server objects respective to their names and does not
1388    * factor any other attribute.  Alphabetic case is significant in 
1389    * comparing names.
1390    *
1391    * @param     server    The Server object to be compared to this 
1392    *                      Server instance
1393    * 
1394    * @return    Zero if the argument is equal to this Server's name, a
1395    *            value less than zero if this Server's name is
1396    *            lexicographically less than the argument, or a value greater
1397    *            than zero if this Server's name is lexicographically
1398    *            greater than the argument
1399    */
1400   public int compareTo(Server server)
1401   {
1402     return this.getName().compareTo(server.getName());
1403   }
1404
1405   /**
1406    * Comparable interface method.
1407    *
1408    * @see #compareTo(Server)
1409    */
1410   public int compareTo(Object obj)
1411   {
1412     return compareTo((Server)obj);
1413   }
1414
1415   /**
1416    * Tests whether two <code>Server</code> objects are equal, based on their 
1417    * names and hosting Cell.
1418    *
1419    * @param otherServer   the Server to test
1420    * @return whether the specifed Server is the same as this Server
1421    */
1422   public boolean equals( Server otherServer )
1423   {
1424     return ( name.equals(otherServer.getName()) ) &&
1425            ( this.getCell().equals(otherServer.getCell()) );
1426   }
1427
1428   /**
1429    * Returns the name of this <CODE>Server</CODE>
1430    *
1431    * @return the name of this <CODE>Server</CODE>
1432    */
1433   public String toString()
1434   {
1435     return getName();
1436   }
1437
1438   /////////////// native methods ////////////////////
1439
1440   /**
1441    * Opens a server for administrative vos use, based on the cell handle 
1442    * provided.  Returns a vos server handle to be used by other 
1443    * methods as a means of identification.
1444    *
1445    * @param cellHandle    a cell handle previously returned by 
1446    *                      a call to {@link #getCellHandle}
1447    * @param serverName    the name of the server for which to retrieve 
1448    *                      a vos handle
1449    * @return a vos handle to the server
1450    * @exception AFSException  If an error occurs in the native code
1451    * @see #getCellHandle
1452    */
1453   protected static native int getVosServerHandle( int cellHandle, 
1454                                                   String serverName )
1455         throws AFSException;
1456
1457   /**
1458    * Closes the given currently open vos server handle.
1459    *
1460    * @param vosHandle   the vos server handle to close
1461    * @exception AFSException  If an error occurs in the native code
1462    */
1463   protected static native void closeVosServerHandle( int vosHandle ) 
1464         throws AFSException; 
1465
1466   /**
1467    * Opens a server for administrative bos use, based on the cell handle 
1468    * provided.  Returns a bos server handle to be used by other methods 
1469    * as a means of identification.
1470    *
1471    * @param cellHandle    a cell handle previously returned by a call 
1472    *                      to {@link #getCellHandle}
1473    * @param serverName    the name of the server for which to retrieve 
1474    *                      a bos handle
1475    * @return a bos handle to the server
1476    * @exception AFSException  If an error occurs in the native code
1477    * @see #getCellHandle
1478    */
1479   protected static native int getBosServerHandle( int cellHandle, 
1480                                                   String serverName )
1481         throws AFSException;
1482
1483   /**
1484    * Closes the given currently open bos server handle.
1485    *
1486    * @param bosHandle   the bos server handle to close
1487    * @exception AFSException  If an error occurs in the native code
1488    */
1489   protected static native void closeBosServerHandle( int bosHandle ) 
1490         throws AFSException; 
1491
1492   /**
1493    * Fills in the information fields of the provided <code>Server</code>. 
1494    *
1495    * @param cellHandle    the handle of the cell to which the server belongs
1496    * @see Cell#getCellHandle
1497    * @param name     the name of the server for which to get the information
1498    * @param server     the <code>Server</code> object in which to fill in 
1499    *                   the information
1500    * @see Server
1501    * @exception AFSException   If an error occurs in the native code
1502    */
1503   protected static native void getServerInfo( int cellHandle, String name, 
1504                                               Server server ) 
1505         throws AFSException;
1506
1507   /**
1508    * Returns the total number of partitions hosted by the server denoted by
1509    * <CODE>serverHandle</CODE>, if the server is a fileserver.
1510    *
1511    * @param cellHandle    the handle of the cell to which the server belongs
1512    * @param serverHandle  the vos handle of the server to which the 
1513    *                      partitions belong
1514    * @return total number of partitions
1515    * @exception AFSException  If an error occurs in the native code
1516    * @see Cell#getCellHandle
1517    * @see #getVosServerHandle
1518    */
1519   protected static native int getPartitionCount( int cellHandle, 
1520                                                   int serverHandle )
1521     throws AFSException;
1522
1523   /**
1524    * Begin the process of getting the partitions on a server.  Returns 
1525    * an iteration ID to be used by subsequent calls to 
1526    * <code>getPartitionsNext</code> and <code>getPartitionsDone</code>.  
1527    *
1528    * @param cellHandle    the handle of the cell to which the server belongs
1529    * @see Cell#getCellHandle
1530    * @param serverHandle  the vos handle of the server to which the 
1531    *                      partitions belong
1532    * @see #getVosServerHandle
1533    * @return an iteration ID
1534    * @exception AFSException  If an error occurs in the native code
1535    */
1536   protected static native int getPartitionsBegin( int cellHandle, 
1537                                                   int serverHandle )
1538     throws AFSException;
1539
1540   /**
1541    * Returns the next partition of the server.  Returns <code>null</code> 
1542    * if there are no more partitions.
1543    *
1544    * @param iterationId   the iteration ID of this iteration
1545    * @see #getPartitionsBegin
1546    * @return the name of the next partition of the server
1547    * @exception AFSException  If an error occurs in the native code
1548    */
1549   protected static native String getPartitionsNextString( int iterationId )
1550     throws AFSException;
1551
1552   /**
1553    * Fills the next partition object of the server.  Returns 0 if there
1554    * are no more partitions, != 0 otherwise
1555    *
1556    * @param iterationId   the iteration ID of this iteration
1557    * @param thePartition   the Partition object in which to fill the 
1558    *                       values of the next partition
1559    * @see #getPartitionsBegin
1560    * @return 0 if there are no more servers, != 0 otherwise
1561    * @exception AFSException  If an error occurs in the native code
1562    */
1563   protected static native int getPartitionsNext( int iterationId, 
1564                                                  Partition thePartition )
1565     throws AFSException;
1566
1567   /**
1568    * Signals that the iteration is complete and will not be accessed anymore.
1569    *
1570    * @param iterationId   the iteration ID of this iteration
1571    * @see #getPartitionsBegin
1572    * @exception AFSException  If an error occurs in the native code
1573    */
1574   protected static native void getPartitionsDone( int iterationId )
1575     throws AFSException;
1576   
1577   /**
1578    * Returns the total number of processes hosted by the server denoted by
1579    * <CODE>serverHandle</CODE>.
1580    *
1581    * @param serverHandle  the vos handle of the server to which the 
1582    *                      processes belong
1583    * @return total number of processes
1584    * @exception AFSException  If an error occurs in the native code
1585    * @see #getVosServerHandle
1586    */
1587   protected static native int getProcessCount( int serverHandle )
1588     throws AFSException;
1589
1590   /**
1591    * Begin the process of getting the processes on a server.  Returns 
1592    * an iteration ID to be used by subsequent calls to 
1593    * <code>getProcessesNext</code> and <code>getProcessesDone</code>.  
1594    *
1595    * @param serverHandle  the bos handle of the server to which the 
1596    *                      processes belong
1597    * @see #getBosServerHandle
1598    * @return an iteration ID
1599    * @exception AFSException  If an error occurs in the native code
1600    */
1601   protected static native int getProcessesBegin( int serverHandle )
1602     throws AFSException;
1603
1604   /**
1605    * Returns the next process of the server.  Returns <code>null</code> 
1606    * if there are no more processes.
1607    *
1608    * @param iterationId   the iteration ID of this iteration
1609    * @see #getProcessesBegin
1610    * @return the name of the next process of the cell
1611    * @exception AFSException  If an error occurs in the native code
1612    */
1613   protected static native String getProcessesNextString( int iterationId )
1614     throws AFSException;
1615
1616   /**
1617    * Fills the next process object of the server.  Returns 0 if there
1618    * are no more processes, != 0 otherwise.
1619    *
1620    * @param serverHandle    the handle of the BOS server that hosts the process
1621    * @see #getBosHandle
1622    * @param iterationId   the iteration ID of this iteration
1623    * @param theProcess    the Process object in which to fill the 
1624    *                      values of the next process
1625    * @see #getProcessesBegin
1626    * @return 0 if there are no more processes, != otherwise
1627    * @exception AFSException  If an error occurs in the native code
1628    */
1629   protected static native int getProcessesNext( int serverHandle, 
1630                                                 int iterationId, 
1631                                                 Process theProcess )
1632     throws AFSException;
1633
1634   /**
1635    * Signals that the iteration is complete and will not be accessed anymore.
1636    *
1637    * @param iterationId   the iteration ID of this iteration
1638    * @see #getProcessesBegin
1639    * @exception AFSException  If an error occurs in the native code
1640    */
1641   protected static native void getProcessesDone( int iterationId )
1642     throws AFSException;
1643
1644   /**
1645    * Returns the total number of keys hosted by the server denoted by
1646    * <CODE>serverHandle</CODE>.
1647    *
1648    * @param serverHandle  the vos handle of the server to which the 
1649    *                      keys belong
1650    * @return total number of keys
1651    * @exception AFSException  If an error occurs in the native code
1652    * @see #getVosServerHandle
1653    */
1654   protected static native int getKeyCount( int serverHandle )
1655     throws AFSException;
1656
1657   /**
1658    * Begin the process of getting the keys of a server.  Returns 
1659    * an iteration ID to be used by subsequent calls to 
1660    * <code>getKeysNext</code> and <code>getKeysDone</code>.  
1661    *
1662    * @param serverHandle  the bos handle of the server to which the keys belong
1663    * @see #getBosServerHandle
1664    * @return an iteration ID
1665    * @exception AFSException  If an error occurs in the native code
1666    */
1667   protected static native int getKeysBegin( int serverHandle )
1668     throws AFSException;
1669
1670   /**
1671    * Returns the next key of the server.  Returns 0 if there
1672    * are no more keys, != 0 otherwise.
1673    *
1674    * @param iterationId   the iteration ID of this iteration
1675    * @param theKey   a {@link Key Key} object, in which to fill in the
1676    *                 properties of the next key.
1677    * @see #getKeysBegin
1678    * @return 0 if there are no more keys, != 0 otherwise
1679    * @exception AFSException  If an error occurs in the native code
1680    */
1681   protected static native int getKeysNext( int iterationId, Key theKey )
1682     throws AFSException;
1683
1684   /**
1685    * Signals that the iteration is complete and will not be accessed anymore.
1686    *
1687    * @param iterationId   the iteration ID of this iteration
1688    * @see #getKeysBegin
1689    * @exception AFSException  If an error occurs in the native code
1690    */
1691   protected static native void getKeysDone( int iterationId )
1692     throws AFSException;
1693
1694   /**
1695    * Returns the total number of BOS administrators associated with the server 
1696    * denoted by <CODE>serverHandle</CODE>.
1697    *
1698    * @param serverHandle  the vos handle of the server to which the 
1699    *                      BOS admins belong
1700    * @return total number of BOS administrators
1701    * @exception AFSException  If an error occurs in the native code
1702    * @see #getVosServerHandle
1703    */
1704   protected static native int getBosAdminCount( int serverHandle )
1705     throws AFSException;
1706
1707   /**
1708    * Begin the process of getting the bos amdinistrators on a server.  Returns 
1709    * an iteration ID to be used by subsequent calls to 
1710    * <code>getBosAdminsNext</code> and <code>getBosAdminsDone</code>.  
1711    *
1712    * @param serverHandle  the bos handle of the server to which the 
1713    *                      partitions belong
1714    * @see #getBosServerHandle
1715    * @return an iteration ID
1716    * @exception AFSException  If an error occurs in the native code
1717    */
1718   protected static native int getBosAdminsBegin( int serverHandle )
1719     throws AFSException;
1720
1721   /**
1722    * Returns the next bos admin of the server.  Returns <code>null</code> 
1723    * if there are no more admins.
1724    *
1725    * @param iterationId   the iteration ID of this iteration
1726    * @see #getBosAdminsBegin
1727    * @return the name of the next admin of the server
1728    * @exception AFSException  If an error occurs in the native code
1729    */
1730   protected static native String getBosAdminsNextString( int iterationId )
1731     throws AFSException;
1732
1733   /**
1734    * Returns the next bos admin of the server.  Returns 0 if there
1735    * are no more admins, != 0 otherwise.
1736    *
1737    * @param cellHandle    the handle of the cell to which these admins belong
1738    * @see #getCellHandle
1739    * @param iterationId   the iteration ID of this iteration
1740    * @see #getBosAdminsBegin
1741    * @param theUser   the user object in which to fill the values of this admin
1742    * @return 0 if no more admins, != 0 otherwise
1743    * @exception AFSException  If an error occurs in the native code
1744    */
1745   protected static native int getBosAdminsNext( int cellHandle, 
1746                                                 int iterationId, User theUser )
1747     throws AFSException;
1748
1749   /**
1750    * Signals that the iteration is complete and will not be accessed anymore.
1751    *
1752    * @param iterationId   the iteration ID of this iteration
1753    * @see #getBosAdminsBegin
1754    * @exception AFSException  If an error occurs in the native code
1755    */
1756   protected static native void getBosAdminsDone( int iterationId )
1757     throws AFSException;
1758
1759   /**
1760    * Adds the given to name to the list of bos administrators on that server.
1761    *
1762    * @param serverHandle  the bos handle of the server to which the 
1763    *                      partitions belong
1764    * @see #getBosServerHandle
1765    * @param adminName   the name of the admin to add to the list
1766    * @exception AFSException  If an error occurs in the native code
1767    */
1768   protected static native void addBosAdmin( int serverHandle, 
1769                                             String adminName )
1770     throws AFSException;
1771
1772   /**
1773    * Removes the given to name from the list of bos administrators on 
1774    * that server.
1775    *
1776    * @param serverHandle  the bos handle of the server to which the 
1777    *                      partitions belong
1778    * @see #getBosServerHandle
1779    * @param adminName   the name of the admin to remove from the list
1780    * @exception AFSException  If an error occurs in the native code
1781    */
1782   protected static native void removeBosAdmin( int serverHandle, 
1783                                                String adminName )
1784     throws AFSException;
1785
1786   /**
1787    * Salvages (restores consistency to) a volume, partition, or server
1788    *
1789    * @param cellHandle    the handle of the cell to which the volume belongs
1790    * @see #getCellHandle
1791    * @param serverHandle  the bos handle of the server on which the 
1792    *                      volume resides
1793    * @see #getBosServerHandle
1794    * @param partitionName  the name of the partition to salvage, 
1795    *                       can be <code>null</code> only if volName is 
1796    *                       <code>null</code>
1797    * @param volName  the name of the volume to salvage, 
1798    *                 can be <code>null</code>
1799    * @param numSalvagers   the number of salvager processes to run in parallel
1800    * @param tempDir   directory to place temporary files, can be 
1801    *                  <code>null</code>
1802    * @param logFile    where salvager log will be written, can be 
1803    *                   <code>null</code>
1804    * @param inspectAllVolumes   whether or not to inspect all volumes, 
1805    *                            not just those marked as active at crash
1806    * @param removeBadlyDamaged   whether or not to remove a volume if it's 
1807    *                             badly damaged
1808    * @param writeInodes   whether or not to record a list of inodes modified
1809    * @param writeRootInodes   whether or not to record a list of AFS 
1810    *                          inodes owned by root
1811    * @param forceDirectory   whether or not to salvage an entire directory 
1812    *                         structure
1813    * @param forceBlockReads   whether or not to force the salvager to read 
1814    *                          the partition
1815    *                          one block at a time and skip badly damaged 
1816    *                          blocks.  Use if partition has disk errors
1817    */
1818   protected static native void salvage( int cellHandle, int serverHandle, 
1819                                         String partitionName, String volName,
1820                                         int numSalvagers, String tempDir, 
1821                                         String logFile, 
1822                                         boolean inspectAllVolumes,
1823                                         boolean removeBadlyDamaged, 
1824                                         boolean writeInodes, 
1825                                         boolean writeRootInodes, 
1826                                         boolean forceDirectory, 
1827                                         boolean forceBlockReads)
1828         throws AFSException;
1829
1830   /**
1831    *  Synchronizes a particular server with the volume location database.
1832    *
1833    * @param cellHandle    the handle of the cell to which the server belongs
1834    * @see #getCellHandle
1835    * @param serverHandle  the vos handle of the server     
1836    * @see #getVosServerHandle
1837    * @param partition   the id of the partition to sync, can be -1 to ignore
1838    * @exception AFSException  If an error occurs in the native code
1839    */
1840   protected static native void syncServerWithVLDB( int cellHandle, 
1841                                                    int serverHandle, 
1842                                                    int partition )
1843     throws AFSException;
1844
1845   /**
1846    *  Synchronizes the volume location database with a particular server.
1847    *
1848    * @param cellHandle    the handle of the cell to which the server belongs
1849    * @see #getCellHandle
1850    * @param serverHandle  the vos handle of the server     
1851    * @see #getVosServerHandle
1852    * @param partition   the id of the partition to sync, can be -1 to ignore
1853    * @param forceDeletion   whether or not to force the deletion of bad volumes
1854    * @exception AFSException  If an error occurs in the native code
1855    */
1856   protected static native void syncVLDBWithServer( int cellHandle, 
1857                                                    int serverHandle, 
1858                                                    int partition, 
1859                                                    boolean forceDeletion )
1860     throws AFSException;
1861
1862   /**
1863    * Retrieves a specified bos log from a server.  Right now this 
1864    * method will simply return a huge String containing the log, but 
1865    * hopefully we can devise a better way to make this work more efficiently.
1866    *
1867    * @param serverHandle  the bos handle of the server to which the key belongs
1868    * @see #getBosServerHandle
1869    * @param logLocation   the full path and name of the desired bos log
1870    * @exception AFSException  If an error occurs in the native code
1871    */
1872   protected static native String getLog( int serverHandle, String logLocation )
1873     throws AFSException;
1874
1875   /**
1876    *  Fills in the restart time fields of the given {@link Server Server} 
1877    *  object. 
1878    *
1879    * @param serverHandle  the bos handle of the server to which the key belongs
1880    * @see #getBosServerHandle
1881    * @param restartType  whether to get the general or binary restart. 
1882    *                     Acceptable values are:<ul>
1883    *                     <li>{@link RESTART_BINARY}</li>
1884    *                     <li>{@link RESTART_GENERAL}</li></ul>     
1885    * @param theServer   the <code>Server</code> object, in which to fill 
1886    *                    the restart time fields
1887    * @exception AFSException  If an error occurs in the native code
1888    */
1889   private static native void getRestartTime( int serverHandle, 
1890                                                int restartType, 
1891                                                ExecutableTime executableTime )
1892     throws AFSException;
1893
1894   /**
1895    *  Sets the restart time of the bos server.
1896    *
1897    * @param serverHandle  the bos handle of the server to which the key belongs
1898    * @see #getBosServerHandle
1899    * @param restartType  whether this is to be a general or binary restart. 
1900    *                     Acceptable values are:<ul>
1901    *                     <li>{@link RESTART_BINARY}</li>
1902    *                     <li>{@link RESTART_GENERAL}</li></ul>
1903    * @param theServer   the server object containing the desired information
1904    * @exception AFSException  If an error occurs in the native code
1905    */
1906   private static native void setRestartTime( int serverHandle, 
1907                                                int restartType, 
1908                                                ExecutableTime executableTime )
1909     throws AFSException;
1910
1911   /**
1912    * Start all server processes.
1913    *
1914    * @param serverHandle  the bos handle of the server to which the 
1915    *                      processes belong
1916    * @see #getBosServerHandle
1917    * @exception AFSException  If an error occurs in the native code
1918    */
1919   protected static native void startAllProcesses( int serverHandle )
1920     throws AFSException;
1921
1922   /**
1923    * Restart all server processes.
1924    *
1925    * @param serverHandle  the bos handle of the server to which the 
1926    *                      processes belong
1927    * @see #getBosServerHandle
1928    * @param restartBosServer   whether or not to restart the bos server as well
1929    * @exception AFSException  If an error occurs in the native code
1930    */
1931   protected static native void restartAllProcesses( int serverHandle, 
1932                                                     boolean restartBosServer )
1933     throws AFSException;
1934
1935   /**
1936    * Stop all server processes.
1937    *
1938    * @param serverHandle  the bos handle of the server to which the 
1939    *                      processes belong
1940    * @see #getBosServerHandle
1941    * @exception AFSException  If an error occurs in the native code
1942    */
1943   protected static native void stopAllProcesses( int serverHandle )
1944     throws AFSException;
1945
1946   /**
1947    * Reclaims all memory being saved by the server portion of the native 
1948    * library. This method should be called when no more <code>Server</code> 
1949    * objects are expected to be used.
1950    */
1951   protected static native void reclaimServerMemory();
1952
1953   /*====================================================================*/
1954   /* INNER CLASSES  */
1955   /*====================================================================*/
1956   public static final class ExecutableTime implements Serializable
1957   {
1958     public static final short NEVER = 0;
1959     public static final short NOW = 1;
1960
1961     public static final short EVERYDAY  = -1;
1962     public static final short SUNDAY    = 0;
1963     public static final short MONDAY    = 1;
1964     public static final short TUESDAY   = 2;
1965     public static final short WEDNESDAY = 3;
1966     public static final short THURSDAY  = 4;
1967     public static final short FRIDAY    = 5;
1968     public static final short SATURDAY  = 6;
1969
1970     static final DecimalFormat formatter = 
1971         (DecimalFormat)DecimalFormat.getInstance();
1972
1973     private short second;
1974     private short minute;
1975     private short hour;
1976     private short day;
1977     private boolean now;
1978     private boolean never;
1979
1980     static
1981     {
1982       formatter.applyPattern("00");
1983     }
1984
1985     /**
1986      * Internal constructor used to construct an empty object that will 
1987      * be passed to JNI for member synchronization of the BOS Server 
1988      * executable time this object represents.
1989      */
1990     ExecutableTime()
1991     {
1992       this.second = (short) 0;
1993       this.minute = (short) 0;
1994       this.hour = (short) 0;
1995       this.day = (short) -1;
1996       this.now = false;
1997       this.never = false;
1998     }
1999
2000     /**
2001      * Constructs an <code>ExecutableTime</code> object that represents either 
2002      * a "<CODE>now</CODE>" <B>or</B> "<CODE>never</CODE>" BOS Executable 
2003      * Restart Time. 
2004      *
2005      * <P>Valid values for the <CODE>type</CODE> parameter are ExecutableTime.NOW
2006      * or ExecutableTime.NEVER.  If a value other than these two is used an
2007      * IllegalArgumentException will be thrown.
2008      *
2009      * @param type   either ExecutableTime.NOW or ExecutableTime.NEVER
2010      * @exception    IllegalArgumentException
2011      *               If a value other than ExecutableTime.NOW or 
2012      *               ExecutableTime.NEVER is used for the <CODE>type</CODE> 
2013      *               parameter.
2014      * @see #isNow()
2015      * @see #isNever()
2016      * @see #Server.ExecutableTime(short, short, short)
2017      */
2018     public ExecutableTime(short type) throws IllegalArgumentException
2019     {
2020       if (type == NOW) {
2021         this.now = true;
2022         this.never = false;
2023       } else if (type == NEVER) {
2024         this.now = false;
2025         this.never = true;
2026       } else {
2027         throw new IllegalArgumentException("You must specify either " + 
2028                                            "ExecutableTime.NOW or " + 
2029                                            "ExecutableTime.NEVER when " +
2030                                            "using this constructor.");
2031       }
2032       this.second = (short) 0;
2033       this.minute = (short) 0;
2034       this.hour = (short) 0;
2035       this.day = (short) -1;
2036     }
2037
2038     /**
2039      * Constructs an <code>ExecutableTime</code> object that may be used to 
2040      * represent a <U>daily</U> BOS Executable Restart Time of a process. 
2041      *
2042      * @param second   the second field for this representation of a 
2043      *                 BOS Server restart time value (range: 0-59)
2044      * @param minute   the minute field for this representation of a 
2045      *                 BOS Server restart time value (range: 0-59)
2046      * @param hour     the hour field for this representation of a BOS 
2047      *                 Server restart time value (range: 0-23)
2048      * @exception      IllegalArgumentException
2049      *                 If any of the parameters values are out of range 
2050      *                 of their respective fields.
2051      * @see #Server.ExecutableTime(short, short, short, short)
2052      * @see #getSecond()
2053      * @see #getMinute()
2054      * @see #getHour()
2055      */
2056     public ExecutableTime(short second, short minute, short hour)
2057       throws IllegalArgumentException
2058     {
2059       this(second, minute, hour, ExecutableTime.EVERYDAY);
2060     }
2061
2062     /**
2063      * Constructs an <code>ExecutableTime</code> object that may be used to 
2064      * represent the BOS Executable Restart Time of a process. 
2065      *
2066      * @param second   the second field for this representation of a 
2067      *                 BOS Server restart time value (range: 0-59)
2068      * @param minute   the minute field for this representation of a 
2069      *                 BOS Server restart time value (range: 0-59)
2070      * @param hour     the hour field for this representation of a BOS 
2071      *                 Server restart time value (range: 0-23)
2072      * @param day      the day field for this representation of a BOS 
2073      *                 Server restart time value.<BR><UL>Valid values include:
2074      *                 <CODE>ExecutableTime.EVERYDAY</CODE> (see also {@link 
2075      *                 #Server.ExecutableTime(short, short, short)})<BR>
2076      *                 <CODE>
2077      *                 ExecutableTime.SUNDAY<BR>
2078      *                 ExecutableTime.MONDAY<BR>
2079      *                 ExecutableTime.TUESDAY<BR>
2080      *                 ExecutableTime.WEDNESDAY<BR>
2081      *                 ExecutableTime.THURSDAY<BR>
2082      *                 ExecutableTime.FRIDAY<BR>
2083      *                 ExecutableTime.SATURDAY<BR>
2084      *                 </CODE></UL>
2085      * @exception      IllegalArgumentException
2086      *                 If any of the parameters values are out of range 
2087      *                 of their respective fields.
2088      * @see #Server.ExecutableTime(short, short, short)
2089      * @see #getSecond()
2090      * @see #getMinute()
2091      * @see #getHour()
2092      * @see #getDay()
2093      */
2094     public ExecutableTime(short second, short minute, short hour, short day) 
2095     {
2096       if ( (0 > second || second > 59) ||
2097            (0 > minute || minute > 59) ||
2098            (0 > hour || hour > 24) ||
2099            (-1 > day || day > 6) ) {
2100         throw new IllegalArgumentException("One of the specified values " + 
2101                                         "are invalid.");
2102       }
2103       this.second = second;
2104       this.minute = minute;
2105       this.hour = hour;
2106       this.day = day;
2107       this.now = false;
2108       this.never = false;
2109     }
2110
2111     /**
2112      * Returns the second of this ExecutableTime object.
2113      *
2114      * @return the second of this ExecutableTime object.
2115      * @exception IllegalStateException 
2116      *            If the executable time this object represents has a value of
2117      *            "<CODE>now</CODE>" or "<CODE>never</CODE>".
2118      */
2119     public short getSecond() throws IllegalStateException 
2120     {
2121       if (now || never) {
2122         throw new IllegalStateException("Executable time is set to 'now' or" +
2123                                                         " 'never'.");
2124       }
2125       return second;
2126     }
2127
2128     /**
2129      * Returns the minute of this ExecutableTime object.
2130      *
2131      * @return the minute of this ExecutableTime object.
2132      * @exception IllegalStateException 
2133      *            If the executable time this object represents has a value of
2134      *            "<CODE>now</CODE>" or "<CODE>never</CODE>".
2135      */
2136     public short getMinute() throws IllegalStateException 
2137     {
2138       if (now || never) {
2139         throw new IllegalStateException("Executable time is set to 'now' or" + 
2140                                         " 'never'.");
2141       }
2142       return minute;
2143     }
2144
2145     /**
2146      * Returns the hour of this ExecutableTime object, in 24 hour time.
2147      *
2148      * @return the hour of this ExecutableTime object.
2149      * @exception IllegalStateException
2150      *            If the executable time this object represents has a value of
2151      *            "<CODE>now</CODE>" or "<CODE>never</CODE>".
2152      */
2153     public short getHour() throws IllegalStateException
2154     {
2155       if (now || never) {
2156         throw new IllegalStateException("Executable time is set to 'now' or" + 
2157                                                         " 'never'.");
2158       }
2159       return hour;
2160     }
2161
2162     /**
2163      * Returns a numeric representation of the day of this ExecutableTime 
2164      * object. If it is daily, the value of ExecutableTime.EVERYDAY is returned.
2165      * 
2166      * <P>Possible return values are:<BR>
2167      * <CODE>
2168      * ExecutableTime.EVERYDAY<BR>
2169      * <BR>
2170      * ExecutableTime.SUNDAY<BR>
2171      * ExecutableTime.MONDAY<BR>
2172      * ExecutableTime.TUESDAY<BR>
2173      * ExecutableTime.WEDNESDAY<BR>
2174      * ExecutableTime.THURSDAY<BR>
2175      * ExecutableTime.FRIDAY<BR>
2176      * ExecutableTime.SATURDAY<BR>
2177      * </CODE>
2178      *
2179      * @return    a numeric representation of the day of this ExecutableTime 
2180      *            object.
2181      * @exception IllegalStateException
2182      *            If the executable time this object represents has a value of
2183      *            "<CODE>now</CODE>" or "<CODE>never</CODE>".
2184      */
2185     public short getDay() throws IllegalStateException
2186     {
2187       if (now || never) {
2188         throw new IllegalStateException("Executable time is set to 'now' or" + 
2189                                                         " 'never'.");
2190       }
2191       return day;
2192     }
2193
2194     /**
2195      * Returns a String representation, name for the day of the week or 
2196      * "Everyday", of this object's day property.
2197      * 
2198      * <P>Possible return values are:
2199      * <PRE>
2200      * Sunday
2201      * Monday
2202      * Tuesday
2203      * Wednesday
2204      * Thursday
2205      * Friday
2206      * Saturday
2207      * 
2208      * Everyday
2209      * </PRE>
2210      *
2211      * @return the day of this ExecutableTime object.
2212      * @exception IllegalStateException
2213      *            If the executable time this object represents has a value of
2214      *            "<CODE>now</CODE>" or "<CODE>never</CODE>".
2215      * @see #getDay()
2216      */
2217     public String getDayString() throws IllegalStateException
2218     {
2219       switch (getDay())
2220       {
2221         case 0:
2222             return "Sunday";
2223         case 1:
2224             return "Monday";
2225         case 2:
2226             return "Tuesday";
2227         case 3:
2228             return "Wednesday";
2229         case 4:
2230             return "Thursday";
2231         case 5:
2232             return "Friday";
2233         case 6:
2234             return "Saturday";
2235         default:
2236             return "Everyday";
2237       }
2238     }
2239
2240     /**
2241      * Returns whether or not the BOS restart time, represented by this 
2242      * ExecutableTime object, is set to "<CODE>now</CODE>" or not.  
2243      * This means that at some point in the past, when someone set it to 
2244      * "<CODE>now</CODE>", the bosserver restarted all its processes,
2245      * and never again.
2246      *
2247      * @return whether or not the restart time is "<CODE>now</CODE>"
2248      */
2249     public boolean isNow()
2250     {
2251       return now;
2252     }
2253
2254     /**
2255      * Returns the second of this ExecutableTime object.
2256      *
2257      * @return the second of this ExecutableTime object.
2258      */
2259     /**
2260      * Returns whether or not the BOS restart time, represented by this 
2261      * ExecutableTime object, is set to "<CODE>never</CODE>" or not.  
2262      * This means that the bosserver will never restart its processes.
2263      *
2264      * @return whether or not the restart time is "<CODE>never</CODE>"
2265      */
2266     public boolean isNever()
2267     {
2268       return never;
2269     }
2270
2271     /**
2272      * Tests whether two <code>ExecutableTime</code> objects are equal, 
2273      * based on a
2274      * comparison of each of their respective properties. If 
2275      * "<CODE>now</CODE>" or "<CODE>never</CODE>" is set in either object, 
2276      * only those properties are analyzed.
2277      *
2278      * @param time   the ExecutableTime to test against
2279      * @return whether the specifed ExecutableTime is the same as this 
2280      * ExecutableTime as defined above
2281      */
2282     public boolean equals( ExecutableTime time )
2283     {
2284       boolean same = false;
2285       try {
2286         same = ( (second == time.getSecond()) &&
2287                  (minute == time.getMinute()) &&
2288                  (hour   == time.getHour()  ) &&
2289                  (day    == time.getDay()   ) );
2290       } catch (Exception e) {
2291         same = ( (now    == time.isNow()    ) &&
2292                  (never  == time.isNever()  ) );
2293
2294       }
2295       return same;
2296     }
2297
2298     /**
2299      * Returns the String representation of time value of this 
2300      * <CODE>ExecutableTime</CODE> object.
2301      *
2302      * <P> Possible return values:<BR>
2303      * <LI> "Now"<BR>
2304      * <LI> "Never"<BR>
2305      * <LI> Day and time string in the form:<BR>&nbsp;&nbsp;&nbsp;&nbsp; 
2306      * <CODE>&#60;day&#62; at &#60;hh&#62;:&#60;MM&#62;[:&#60;ss&#62;]</CODE>
2307      * <BR><BR>
2308      *
2309      * <B>Example Return Values:</B><PRE>
2310      * Sunday at 04:00
2311      * Sunday at 05:10:30
2312      * Everyday at 20:00</PRE>
2313      *
2314      * @return the String representation of this <CODE>ExecutableTime</CODE> 
2315      * object
2316      */
2317     public String toString()
2318     {
2319       if (now) {
2320         return "Now";
2321       } else if (never) {
2322         return "Never";
2323       } else {
2324         try {
2325           if (second != 0) {
2326             return getDayString() + " at " + 
2327                 ExecutableTime.formatter.format(hour) + ":" + 
2328                 ExecutableTime.formatter.format(minute) + ":" + 
2329                 ExecutableTime.formatter.format(second);
2330           } else {
2331             return getDayString() + " at " + 
2332                 ExecutableTime.formatter.format(hour) + ":" + 
2333                 ExecutableTime.formatter.format(minute);
2334           }
2335         } catch (Exception e) {
2336           return "(unknown)";
2337         }
2338       }
2339     }
2340
2341   }
2342   /*====================================================================*/
2343
2344 }
2345
2346
2347
2348
2349
2350
2351