1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 package com.sun.dhcpmgr.data;
  26 
  27 import java.util.ArrayList;
  28 import java.util.Arrays;
  29 import java.io.Serializable;
  30 import com.sun.dhcpmgr.data.qualifier.*;
  31 
  32 /**
  33  * DhcpdOptions models the option settings for the in.dhcpd daemon.  We read
  34  * and write the option settings in the daemon's defaults file.
  35  * Getter and setter methods are provided for each individual option.
  36  */
  37 
  38 public class DhcpdOptions implements DhcpConfigOpts, Serializable {
  39     /* The list of facility choices the user may select from for logging */
  40     private static final Integer [] loggingFacilities = {
  41         new Integer(0), new Integer(1), new Integer(2), new Integer(3),
  42         new Integer(4), new Integer(5), new Integer(6), new Integer(7)
  43     };
  44 
  45     // Store the option settings here
  46     private ArrayList options;
  47 
  48     /**
  49      *  Dirty flag. Set after a clear or a set on an option.
  50      */
  51     private boolean dirty = false;
  52 
  53     public DhcpdOptions() {
  54         options = new ArrayList();
  55     }
  56 
  57     public DhcpdOptions(DhcpResource [] opts) {
  58         options = new ArrayList(Arrays.asList(opts));
  59     }
  60 
  61     public Object clone() {
  62         DhcpdOptions o = new DhcpdOptions();
  63         o.options = (ArrayList)options.clone();
  64         return o;
  65     }
  66 
  67     /**
  68      * Test whether a particular option is set.
  69      * @param key
  70      *   The name of the option to set.
  71      * @return
  72      *   True if the option is set, otherwise false.
  73      */
  74     public boolean isSet(String key) {
  75         return internalIsSet(key);
  76     }
  77 
  78     /**
  79      * Set an option to a supplied value.
  80      * @param key
  81      *   The name of the option to set.
  82      * @param value
  83      *   The value of the option.
  84      */
  85     public void set(String key, String value) {
  86         set(key, value, false);
  87     }
  88 
  89     /**
  90      * Set an option to a supplied value, or add a comment line to the
  91      * table.
  92      * @param key
  93      *   The name of the option to set.
  94      * @param value
  95      *   The value of the option.
  96      * @param comment
  97      *   true if this is a comment, in which case value is ignored
  98      * and the comment text is contained entirely in key.
  99      */
 100     public void set(String key, String value, boolean comment) {
 101         internalSet(key, value, comment);
 102 
 103         /*
 104          * Ensure that the run mode is kept consistent with the
 105          * configuration parameters.  Mgt. tools rely on this!
 106          */
 107         if (key.equals(DSVC_CK_PATH)) {
 108             internalSet(DSVC_CK_RUN_MODE, DSVC_CV_SERVER);
 109         } else if (key.equals(DSVC_CK_RELAY_DESTINATIONS)) {
 110             internalSet(DSVC_CK_RUN_MODE, DSVC_CV_RELAY);
 111         } else if (key.equals(DSVC_CK_RESOURCE)) {
 112             internalSet(DSVC_CK_RUN_MODE, DSVC_CV_SERVER);
 113         }
 114     }
 115 
 116     /**
 117      * Clear an option.
 118      * @param key
 119      *   The name of the option to clear.
 120      */
 121     public void clear(String key) {
 122         internalClear(key);
 123 
 124         if (key.equals(DSVC_CK_RELAY_DESTINATIONS)) {
 125             internalSet(DSVC_CK_RUN_MODE, DSVC_CV_SERVER);
 126         }
 127     }
 128 
 129     /**
 130      * Return the value of an option setting; null if it's not set.
 131      * @param key
 132      *   The option whose value is to be retrieved.
 133      * @return
 134      *   The value of an option setting; null if it's not set.
 135      */
 136     public String valueOf(String key) {
 137         return internalValueOf(key);
 138     }
 139 
 140     // Test whether a particular option is set
 141     private boolean internalIsSet(String key) {
 142         DhcpResource res = new DhcpResource();
 143         res.setKey(key);
 144         return options.contains(res);
 145     }
 146 
 147     // Set an option to a supplied value
 148     private void internalSet(String key, String value) {
 149         internalSet(key, value, false);
 150     }
 151 
 152     /**
 153      * Set an option to a supplied value, or add a comment line to the
 154      * table.
 155      * @param key The name of the option to set
 156      * @param value The value of the option
 157      * @param comment true if this is a comment, in which case value is ignored
 158      * and the comment text is contained entirely in key.
 159      */
 160     private void internalSet(String key, String value, boolean comment) {
 161         DhcpResource res = new DhcpResource(key, value, comment);
 162         int i = options.indexOf(res);
 163         if (i != -1) {
 164             DhcpResource existing = (DhcpResource)options.get(i);
 165 
 166             if (!existing.getValue().equals(res.getValue())) {
 167                 options.set(i, res);
 168                 dirty = true;
 169             }
 170         } else {
 171             options.add(res);
 172             dirty = true;
 173         }
 174     }
 175 
 176     // Clear an option
 177     private void internalClear(String key) {
 178         DhcpResource res = new DhcpResource();
 179         res.setKey(key);
 180         int i = options.indexOf(res);
 181         if (i != -1) {
 182             options.remove(i);
 183             dirty = true;
 184         }
 185     }
 186 
 187     /**
 188      * Return the value of an option setting; null if it's not set
 189      * @param key The option whose value is to be retrieved
 190      * @return The value of an option setting; null if it's not set
 191      */
 192     private String internalValueOf(String key) {
 193         DhcpResource res = new DhcpResource();
 194         res.setKey(key);
 195         int i = options.indexOf(res);
 196         if (i != -1) {
 197             return ((DhcpResource)options.get(i)).getValue();
 198         } else {
 199             return null;
 200         }
 201     }
 202 
 203     /**
 204      * Return all of the option settings as an array
 205      * @return An array of Objects which will all be DhcpResources
 206      */
 207     public Object [] getAll() {
 208         return options.toArray();
 209     }
 210 
 211     /**
 212      * Test to see whether or not the daemon is enabled.
 213      * @return true if daemon is enabled, false if not.
 214      */
 215     public boolean isDaemonEnabled() {
 216         return DSVC_CV_TRUE.equals(valueOf(DSVC_CK_DAEMON_ENABLED));
 217     }
 218 
 219     /**
 220      * Set daemon enabled or disabled
 221      * @param state true for enabled, false for disabled
 222      */
 223     public void setDaemonEnabled(boolean state) {
 224         set(DSVC_CK_DAEMON_ENABLED, state ? DSVC_CV_TRUE : DSVC_CV_FALSE);
 225     }
 226 
 227     /**
 228      * Set the DhcpDatastore attributes.
 229      * @param resource the data store resource attribute
 230      * @param location the data store location attribute
 231      * @param config the data store config attribute
 232      * @param version the data store version attribute
 233      */
 234     public void setDhcpDatastore(String resource, String location,
 235         String config, int version) {
 236         setResource(resource);
 237         setPath(location);
 238         setConfig(config);
 239         setResourceVersion(version);
 240     } // setDhcpDatastore
 241 
 242     /**
 243      * Set the DhcpDatastore attributes.
 244      * @param datastore a datastore object whose attributes
 245      * are the desired attributes.
 246      */
 247     public void setDhcpDatastore(DhcpDatastore datastore) {
 248         setResource(datastore.getResource());
 249         setPath(datastore.getLocation());
 250         setConfig(datastore.getConfig());
 251         setResourceVersion(datastore.getVersion());
 252     } // setDhcpDatastore
 253 
 254     /**
 255      * Set the DhcpDatastore attributes.
 256      * @param resource the data store resource attribute
 257      * @param location the data store location attribute
 258      * @param config the data store config attribute
 259      * @param version the data store version attribute
 260      */
 261     public DhcpDatastore getDhcpDatastore() {
 262         return (new DhcpDatastore(getResource(), getPath(),
 263             getConfig(), getResourceVersion()));
 264     } // getDhcpDatastore
 265 
 266     /**
 267      * Set the resource (aka data store) in which DHCP data is stored.
 268      * This automatically also sets the run mode to server.
 269      * @param s Unique name of resource
 270      */
 271     public void setResource(String s) {
 272         set(DSVC_CK_RESOURCE, s);
 273     }
 274 
 275     /**
 276      * Retrieve the name of the resource/data store used for DHCP.
 277      * @return The unique name of the resource; null if not set
 278      */
 279     public String getResource() {
 280         return valueOf(DSVC_CK_RESOURCE);
 281     }
 282 
 283     /**
 284      * Set the version of the resource in which DHCP data is stored.
 285      * @param i version number
 286      */
 287     public void setResourceVersion(int i) {
 288         set(DSVC_CK_CONVER, Integer.toString(i));
 289     }
 290 
 291     /**
 292      * Retrieve the version of the resource/data store used for DHCP.
 293      * @return The version number or -1 if not valid.
 294      */
 295     public int getResourceVersion() {
 296         try {
 297             return Integer.parseInt(valueOf(DSVC_CK_CONVER));
 298         } catch (NumberFormatException e) {
 299             return -1;
 300         }
 301     }
 302 
 303     /**
 304      * Set the path within the resource in which to place the tables.
 305      * For files, this is a Unix pathname; for NIS+, the directory name.
 306      * @param s The path
 307      */
 308     public void setPath(String s) {
 309         set(DSVC_CK_PATH, s);
 310     }
 311 
 312     /**
 313      * Get the path used for data storage.
 314      * @return The path within the resource; null if not set
 315      */
 316     public String getPath() {
 317         return valueOf(DSVC_CK_PATH);
 318     }
 319 
 320     /**
 321      * Set the config for the resource.
 322      * @param s The config
 323      */
 324     public void setConfig(String s) {
 325         if (s != null) {
 326             set(DSVC_CK_RESOURCE_CONFIG, s);
 327         } else {
 328             clear(DSVC_CK_RESOURCE_CONFIG);
 329         }
 330     }
 331 
 332     /**
 333      * Get the config for data store.
 334      * @return The config; null if not set
 335      */
 336     public String getConfig() {
 337         return valueOf(DSVC_CK_RESOURCE_CONFIG);
 338     }
 339 
 340     /**
 341      * Set the hosts resource (aka data store) in which host data is stored.
 342      * @param s Unique name of resource
 343      */
 344     public void setHostsResource(String s) {
 345         set(DSVC_CK_HOSTS_RESOURCE, s);
 346     }
 347 
 348     /**
 349      * Retrieve the name of the resource/data store used for hosts.
 350      * @return The unique name of the resource; null if not set
 351      */
 352     public String getHostsResource() {
 353         return valueOf(DSVC_CK_HOSTS_RESOURCE);
 354     }
 355 
 356     /**
 357      * Set the domain within the hosts resource in which to place the tables.
 358      * For files resource, this value is meaningless.
 359      * @param s The domain
 360      */
 361     public void setHostsDomain(String s) {
 362         set(DSVC_CK_HOSTS_DOMAIN, s);
 363     }
 364 
 365     /**
 366      * Get the domain used for hosts data storage.
 367      * @return The domain within the resource; null if not set
 368      */
 369     public String getHostsDomain() {
 370         return valueOf(DSVC_CK_HOSTS_DOMAIN);
 371     }
 372 
 373     /**
 374      * Test whether BOOTP compatibility is enabled.
 375      * @return true if BOOTP compatibility is enabled.
 376      */
 377     public boolean isBootpCompatible() {
 378         return isSet(DSVC_CK_BOOTP_COMPAT);
 379     }
 380 
 381     /**
 382      * Enable or disable BOOTP compatibility.
 383      * @param state true if BOOTP compatibility is enabled, false if not.
 384      * @param isAutomatic true if automatic allocation is allowed.
 385      */
 386     public void setBootpCompatible(boolean state, boolean isAutomatic) {
 387         if (state) {
 388             if (isAutomatic) {
 389                 set(DSVC_CK_BOOTP_COMPAT, DSVC_CV_AUTOMATIC);
 390             } else {
 391                 set(DSVC_CK_BOOTP_COMPAT, DSVC_CV_MANUAL);
 392             }
 393         } else {
 394             clear(DSVC_CK_BOOTP_COMPAT);
 395         }
 396     }
 397 
 398     /**
 399      * Test whether BOOTP compatibility is automatic or manual
 400      * @return true if BOOTP compatibility is automatic.
 401      */
 402     public boolean isBootpAutomatic() {
 403         return DSVC_CV_AUTOMATIC.equals(valueOf(DSVC_CK_BOOTP_COMPAT));
 404     }
 405 
 406     /**
 407      * Test whether relay hop limit is set.
 408      * @return true if the limit is set, false if default value is used.
 409      */
 410     public boolean isRelayHops() {
 411         return isSet(DSVC_CK_RELAY_HOPS);
 412     }
 413 
 414     /**
 415      * Set the relay hop limit.
 416      * @param state true if hop limit should be set, false if not
 417      * @param hops Number of hops to limit forwarding to
 418      */
 419     public void setRelayHops(boolean state, Integer hops) {
 420         if (state) {
 421             set(DSVC_CK_RELAY_HOPS, hops.toString());
 422         } else {
 423             clear(DSVC_CK_RELAY_HOPS);
 424         }
 425     }
 426 
 427     /**
 428      * Get the relay hop limit.
 429      * @return The number of hops currently set, or null if this isn't set.
 430      */
 431     public Integer getRelayHops() {
 432         String hops = valueOf(DSVC_CK_RELAY_HOPS);
 433         if (hops != null) {
 434             return new Integer(hops);
 435         } else {
 436             return null;
 437         }
 438     }
 439 
 440     /**
 441      * Test whether a network interface list is set; failure to set an interface
 442      * list implies that all interfaces will be monitored.
 443      * @return true if an interface list is set
 444      */
 445     public boolean isInterfaces() {
 446         return isSet(DSVC_CK_INTERFACES);
 447     }
 448 
 449     /**
 450      * Set the network interface list.
 451      * @param state true if interface list is to be set, false if it should be
 452      * cleared
 453      * @param list A comma-separated list of interface names
 454      */
 455     public void setInterfaces(boolean state, String list) {
 456         if (state) {
 457             set(DSVC_CK_INTERFACES, list);
 458         } else {
 459             clear(DSVC_CK_INTERFACES);
 460         }
 461     }
 462 
 463     /**
 464      * Get the list of network interfaces.
 465      * @return The comma-separated list of interfaces; null if not set
 466      */
 467     public String getInterfaces() {
 468         return valueOf(DSVC_CK_INTERFACES);
 469     }
 470 
 471     /**
 472      * Test whether ICMP address verification is enabled
 473      * @return true if ICMP verification is performed
 474      */
 475     public boolean isICMPVerify() {
 476         /*
 477          * Use this double-inverse comparison so that the default behavior of
 478          * ICMP enabled is handled correctly.
 479          */
 480         return !DSVC_CV_FALSE.equals(valueOf(DSVC_CK_ICMP_VERIFY));
 481     }
 482 
 483     /**
 484      * Set ICMP verification
 485      * @param state true if verification should be done, false otherwise
 486      */
 487     public void setICMPVerify(boolean state) {
 488         set(DSVC_CK_ICMP_VERIFY, state ? DSVC_CV_TRUE : DSVC_CV_FALSE);
 489     }
 490 
 491     /**
 492      * Test whether offer cache timeout is set
 493      * @return true if it is set
 494      */
 495     public boolean isOfferTtl() {
 496         return isSet(DSVC_CK_OFFER_CACHE_TIMEOUT);
 497     }
 498 
 499     /**
 500      * Set offer cache timeout value
 501      * @param state true if offer cache timeout value is set, false if server's
 502      * default will be used instead
 503      * @param time Number of seconds to hold offers in the cache
 504      */
 505     public void setOfferTtl(boolean state, Integer time) {
 506         if (state) {
 507             set(DSVC_CK_OFFER_CACHE_TIMEOUT, time.toString());
 508         } else {
 509             clear(DSVC_CK_OFFER_CACHE_TIMEOUT);
 510         }
 511     }
 512 
 513     /**
 514      * Get the offer cache timeout value
 515      * @return timeout value set, or null if server default is used
 516      */
 517     public Integer getOfferTtl() {
 518         String s = valueOf(DSVC_CK_OFFER_CACHE_TIMEOUT);
 519         if (s != null) {
 520             return new Integer(s);
 521         } else {
 522             return null;
 523         }
 524     }
 525 
 526     /**
 527      * Test whether server is running in relay mode
 528      * @return true if running as relay
 529      */
 530     public boolean isRelay() {
 531         return DSVC_CV_RELAY.equals(valueOf(DSVC_CK_RUN_MODE));
 532     }
 533 
 534     /**
 535      * Set relay mode and server list
 536      * @param state true if relay mode is desired, false for normal server
 537      * @param servers list of servers to which requests should be forwarded
 538      */
 539     public void setRelay(boolean state, String servers) {
 540         if (state) {
 541             set(DSVC_CK_RELAY_DESTINATIONS, servers);
 542         } else {
 543             clear(DSVC_CK_RELAY_DESTINATIONS);
 544         }
 545     }
 546 
 547     /**
 548      * Get list of server targets for relay
 549      * @return list of relay targets; null if not set
 550      */
 551     public String getRelay() {
 552         return valueOf(DSVC_CK_RELAY_DESTINATIONS);
 553     }
 554 
 555     /**
 556      * Test for server automatic reload of dhcptab
 557      * @return true if server is rescanning dhcptab
 558      */
 559     public boolean isRescan() {
 560         return isSet(DSVC_CK_RESCAN_INTERVAL);
 561     }
 562 
 563     /**
 564      * Set the rescan interval
 565      * @param state true if rescanning is enabled, false if not
 566      * @param interval number of minutes between rescans
 567      */
 568     public void setRescan(boolean state, Integer interval) {
 569         if (state) {
 570             set(DSVC_CK_RESCAN_INTERVAL, interval.toString());
 571         } else {
 572             clear(DSVC_CK_RESCAN_INTERVAL);
 573         }
 574     }
 575 
 576     /**
 577      * Get the rescan interval
 578      * @return the rescan interval in minutes, or null if rescan is not enabled
 579      */
 580     public Integer getRescan() {
 581         String s = valueOf(DSVC_CK_RESCAN_INTERVAL);
 582         if (s != null) {
 583             return new Integer(s);
 584         } else {
 585             return null;
 586         }
 587     }
 588 
 589     /**
 590      * Test whether ownerip
 591      * @return true if ownerip
 592      */
 593     public boolean isOwnerip() {
 594         return isSet(DSVC_CK_OWNER_IP);
 595     }
 596 
 597     /**
 598      * Set ownerip server list
 599      * @param state true if ownerip is desired, false for normal server
 600      * @param ownerips list of servers ownerips
 601      */
 602     public void setOwnerip(boolean state, String ownerips) {
 603         if (state) {
 604             set(DSVC_CK_OWNER_IP, ownerips);
 605         } else {
 606             clear(DSVC_CK_OWNER_IP);
 607         }
 608     }
 609 
 610     /**
 611      * Get list of server targets for ownerip
 612      * @return list of ownerip targets; null if not set
 613      */
 614     public String getOwnerip() {
 615         return valueOf(DSVC_CK_OWNER_IP);
 616     }
 617 
 618 
 619     /**
 620      * Test for server dynamic DNS updates
 621      * @return true if server is updating DNS
 622      */
 623     public boolean isDnsUpdated() {
 624         return isSet(DSVC_CK_NSU_TIMEOUT);
 625     }
 626 
 627     /**
 628      * Set the DNS update timeout value
 629      * @param state true if DNS updates are enabled, false if not
 630      * @param timeout number of seconds before timeout
 631      */
 632     public void setDnsTimeout(boolean state, Integer timeout) {
 633         if (state) {
 634             set(DSVC_CK_NSU_TIMEOUT, timeout.toString());
 635         } else {
 636             clear(DSVC_CK_NSU_TIMEOUT);
 637         }
 638     }
 639 
 640     /**
 641      * Get the DNS update timeout value
 642      * @return the timeout in seconds, or null if DNS updates are not enabled
 643      */
 644     public Integer getDnsTimeout() {
 645         String s = valueOf(DSVC_CK_NSU_TIMEOUT);
 646         if (s != null) {
 647             return new Integer(s);
 648         } else {
 649             return null;
 650         }
 651     }
 652 
 653     /**
 654      * Test for verbose logging mode
 655      * @return true if verbose logging, false for normal
 656      */
 657     public boolean isVerbose() {
 658         return DSVC_CV_TRUE.equals(valueOf(DSVC_CK_VERBOSE));
 659     }
 660 
 661     /**
 662      * Set verbose logging mode
 663      * @param state true for verbose, false for normal
 664      */
 665     public void setVerbose(boolean state) {
 666         set(DSVC_CK_VERBOSE, state ? DSVC_CV_TRUE : DSVC_CV_FALSE);
 667     }
 668 
 669 
 670     /**
 671      * Test for transaction logging mode.
 672      * @return true if transaction logging is enabled
 673      */
 674     public boolean isLogging() {
 675         return isSet(DSVC_CK_LOGGING_FACILITY);
 676     }
 677 
 678     /**
 679      * Get the syslog facility number used for transaction logging
 680      * @return facility number, which will be between 0 and 7
 681      */
 682     public Integer getLogging() {
 683         String s = valueOf(DSVC_CK_LOGGING_FACILITY);
 684         if (s != null) {
 685             return new Integer(s);
 686         } else {
 687             return null;
 688         }
 689     }
 690 
 691     /**
 692      * Set transaction logging
 693      * @param state true to enable transaction logging, false to disable
 694      * @param value syslog facility number 0-7 used for logging
 695      */
 696     public void setLogging(boolean state, Integer value) {
 697         if (state) {
 698             set(DSVC_CK_LOGGING_FACILITY, value.toString());
 699         } else {
 700             clear(DSVC_CK_LOGGING_FACILITY);
 701         }
 702     }
 703 
 704     /**
 705      * Get the list of logging facility choices
 706      * @return an array of facility numbers
 707      */
 708     public static Integer [] getLoggingFacilities() {
 709         return loggingFacilities;
 710     }
 711 
 712     /**
 713      * Return an indicator of whether the parameters may have been changed
 714      * by a set() or a clear() since the last call to clearDirty().
 715      *
 716      * @return
 717      *   True if a set() or a clear() has occurred since the last call to
 718      *   clearDirty(), otherwise false.
 719      */
 720     public boolean isDirty() {
 721         return dirty;
 722     }
 723 
 724     /**
 725      * Set the dirty indicator to false. Any subsequent calls to set() or
 726      * clear() may set the dirty flag.
 727      */
 728     public void clearDirty() {
 729         dirty = false;
 730     }
 731 
 732     /**
 733      * Get the parameters qualifier.
 734      *
 735      * @param key
 736      *   Parameters keyword.
 737      * @return
 738      *   The qualifier for the parameter if one exists, otherwise null.
 739      */
 740     public Qualifier getQualifier(String key) {
 741         Qualifier qualifier = null;
 742 
 743         if (key.equals(DSVC_CK_BOOTP_COMPAT)) {
 744             qualifier =
 745                     new QualifierImpl(DSVC_CK_BOOTP_COMPAT, false, false,
 746                             new QualifierStringEnum(
 747                                 new String[] {
 748                                     DSVC_CV_AUTOMATIC,
 749                                     DSVC_CV_MANUAL
 750                                 }));
 751         } else if (key.equals(DSVC_CK_CACHE_TIMEOUT)) {
 752             qualifier =
 753                     new QualifierImpl(DSVC_CK_CACHE_TIMEOUT, false, false,
 754                             new QualifierIntegerRange(
 755                                 0,
 756                                 Integer.MAX_VALUE));
 757 
 758         } else if (key.equals(DSVC_CK_CONVER)) {
 759             qualifier =
 760                     new QualifierImpl(DSVC_CK_CONVER, true, false,
 761                             new QualifierInteger());
 762 
 763         } else if (key.equals(DSVC_CK_DAEMON_ENABLED)) {
 764             qualifier =
 765                     new QualifierImpl(DSVC_CK_DAEMON_ENABLED, true, false,
 766                             new QualifierBoolean(
 767                                 DSVC_CV_TRUE,
 768                                 DSVC_CV_FALSE));
 769 
 770         } else if (key.equals(DSVC_CK_DBG_MEMORY_NET)) {
 771             qualifier =
 772                     new QualifierImpl(DSVC_CK_DBG_MEMORY_NET, false, true,
 773                             new QualifierIntegerRange(
 774                                 0,
 775                                 Integer.MAX_VALUE));
 776 
 777         } else if (key.equals(DSVC_CK_DBG_PORT_OFFSET)) {
 778             qualifier =
 779                     new QualifierImpl(DSVC_CK_DBG_PORT_OFFSET, false, true,
 780                             new QualifierIntegerRange(
 781                                 0,
 782                                 Integer.MAX_VALUE));
 783 
 784         } else if (key.equals(DSVC_CK_HOSTS_DOMAIN)) {
 785             qualifier =
 786                     new QualifierImpl(DSVC_CK_HOSTS_DOMAIN, true, false,
 787                             new QualifierStringEnum(
 788                                 new String[] {
 789                                     DSVC_CV_DNS
 790                                 }));
 791         } else if (key.equals(DSVC_CK_HOSTS_RESOURCE)) {
 792             qualifier =
 793                     new QualifierImpl(DSVC_CK_HOSTS_RESOURCE, true, false,
 794                             new QualifierStringEnum(
 795                                 new String[] {
 796                                     DSVC_CV_DNS,
 797                                     DSVC_CV_FILES
 798                                 }));
 799         } else if (key.equals(DSVC_CK_ICMP_VERIFY)) {
 800             qualifier =
 801                     new QualifierImpl(DSVC_CK_ICMP_VERIFY, false, false,
 802                             new QualifierBoolean(
 803                                 DSVC_CV_TRUE,
 804                                 DSVC_CV_FALSE));
 805 
 806         } else if (key.equals(DSVC_CK_INTERFACES)) {
 807             qualifier =
 808                     new QualifierImpl(DSVC_CK_INTERFACES, false, false,
 809                             new QualifierArray(
 810                                 new QualifierString()));
 811 
 812         } else if (key.equals(DSVC_CK_LEASE_MIN_LRU)) {
 813             qualifier =
 814                     new QualifierImpl(DSVC_CK_LEASE_MIN_LRU, false, true,
 815                             new QualifierIntegerRange(
 816                                 0,
 817                                 Integer.MAX_VALUE));
 818 
 819         } else if (key.equals(DSVC_CK_LOGGING_FACILITY)) {
 820             qualifier =
 821                     new QualifierImpl(DSVC_CK_LOGGING_FACILITY, false, false,
 822                             new QualifierIntegerRange(
 823                                 DSVC_CV_LOGGING_FACILITY_MIN,
 824                                 DSVC_CV_LOGGING_FACILITY_MAX));
 825 
 826         } else if (key.equals(DSVC_CK_MAX_CLIENTS)) {
 827             qualifier =
 828                     new QualifierImpl(DSVC_CK_MAX_CLIENTS, false, true,
 829                             new QualifierIntegerRange(
 830                                 -1,
 831                                 Integer.MAX_VALUE));
 832 
 833         } else if (key.equals(DSVC_CK_MAX_THREADS)) {
 834             qualifier =
 835                     new QualifierImpl(DSVC_CK_MAX_THREADS, false, true,
 836                             new QualifierIntegerRange(
 837                                 -1,
 838                                 Integer.MAX_VALUE));
 839 
 840         } else if (key.equals(DSVC_CK_OFFER_CACHE_TIMEOUT)) {
 841             qualifier =
 842                     new QualifierImpl(DSVC_CK_OFFER_CACHE_TIMEOUT, false, false,
 843                             new QualifierIntegerRange(
 844                                 0,
 845                                 Integer.MAX_VALUE));
 846 
 847         } else if (key.equals(DSVC_CK_PATH)) {
 848             qualifier =
 849                     new QualifierImpl(DSVC_CK_PATH, true, false,
 850                             new QualifierString());
 851 
 852         } else if (key.equals(DSVC_CK_RELAY_DESTINATIONS)) {
 853             qualifier =
 854                     new QualifierImpl(DSVC_CK_RELAY_DESTINATIONS, false, false,
 855                             new QualifierArray(
 856                                 new QualifierOr(
 857                                     new QualifierFQDN(),
 858                                     new QualifierIPv4())));
 859 
 860         } else if (key.equals(DSVC_CK_RELAY_HOPS)) {
 861             qualifier =
 862                     new QualifierImpl(DSVC_CK_RELAY_HOPS, false, false,
 863                             new QualifierIntegerRange(
 864                                 0,
 865                                 Integer.MAX_VALUE));
 866 
 867         } else if (key.equals(DSVC_CK_RESCAN_INTERVAL)) {
 868             qualifier =
 869                     new QualifierImpl(DSVC_CK_RESCAN_INTERVAL, false, false,
 870                             new QualifierIntegerRange(
 871                                 0, Integer.MAX_VALUE));
 872 
 873         } else if (key.equals(DSVC_CK_OWNER_IP)) {
 874             qualifier =
 875                     new QualifierImpl(DSVC_CK_OWNER_IP, false, false,
 876                             new QualifierArray(
 877                                 new QualifierIPv4()));
 878 
 879         } else if (key.equals(DSVC_CK_RESOURCE)) {
 880             qualifier =
 881                     new QualifierImpl(DSVC_CK_RESOURCE, true, false,
 882                             new QualifierString());
 883 
 884         } else if (key.equals(DSVC_CK_RESOURCE_CONFIG)) {
 885             qualifier =
 886                     new QualifierImpl(DSVC_CK_RESOURCE_CONFIG, true, false,
 887                             new QualifierString());
 888 
 889         } else if (key.equals(DSVC_CK_RUN_MODE)) {
 890             qualifier =
 891                     new QualifierImpl(DSVC_CK_RUN_MODE, true, false,
 892                             new QualifierStringEnum(
 893                                 new String[] {
 894                                     DSVC_CV_SERVER,
 895                                     DSVC_CV_RELAY
 896                                 }));
 897         } else if (key.equals(DSVC_CK_RENOG_INTERVAL)) {
 898             qualifier =
 899                     new QualifierImpl(DSVC_CK_RENOG_INTERVAL, false, false,
 900                             new QualifierIntegerRange(
 901                                 0,
 902                                 Integer.MAX_VALUE));
 903 
 904         } else if (key.equals(DSVC_CK_NSU_TIMEOUT)) {
 905             qualifier =
 906                     new QualifierImpl(DSVC_CK_NSU_TIMEOUT, false, false,
 907                             new QualifierIntegerRange(
 908                                 -1,
 909                                 Integer.MAX_VALUE));
 910 
 911         } else if (key.equals(DSVC_CK_VERBOSE)) {
 912             qualifier =
 913                     new QualifierImpl(DSVC_CK_VERBOSE, false, false,
 914                             new QualifierBoolean(
 915                                 DSVC_CV_TRUE,
 916                                 DSVC_CV_FALSE));
 917         }
 918 
 919         return qualifier;
 920     }
 921 
 922     /**
 923      * Convert this object to a String representation
 924      */
 925     public String toString() {
 926         StringBuffer b = new StringBuffer();
 927         for (int i = 0; i < options.size(); ++i) {
 928             DhcpResource res = (DhcpResource)options.get(i);
 929             b.append(res.getKey());
 930             String s = res.getValue();
 931             if (s != null) {
 932                 b.append('=');
 933                 b.append(s);
 934             }
 935             b.append('\n');
 936         }
 937         return b.toString();
 938     }
 939 }