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, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * ident        "%Z%%M% %I%     %E% SMI"
  24  *
  25  * Copyright 1998-2002 Sun Microsystems, Inc.  All rights reserved.
  26  * Use is subject to license terms.
  27  */
  28 
  29 package com.sun.dhcpmgr.data;
  30 
  31 import java.util.*;
  32 import java.text.MessageFormat;
  33 
  34 /**
  35  * Macro is a simple data class which encapsulates a macro record in
  36  * the dhcptab.  See dhcptab(4) for the gory details on macros.
  37  * @see DhcptabRecord
  38  * @see Option
  39  */
  40 public class Macro extends DhcptabRecord implements Cloneable {
  41 
  42     private boolean valueClean = false;
  43     private Vector options;
  44 
  45     // Definition for attribute limits
  46     public final static short MAX_NAME_SIZE = 128;
  47 
  48     // Value used to edit a boolean symbol of a macro
  49     public final static String BOOLEAN_EDIT_VALUE = "_NULL_VALUE_";
  50 
  51     // Serialization id for this class
  52     static final long serialVersionUID = -5255083189703724489L;
  53 
  54     public Macro() {
  55         super("", DhcptabRecord.MACRO, "");
  56         options = new Vector();
  57     }
  58     
  59     public Macro(String name) throws ValidationException {
  60         this();
  61         setKey(name);
  62     }
  63 
  64     public Macro(String name, String expansion) throws ValidationException {
  65         this(name, expansion, DhcptabRecord.DEFAULT_SIGNATURE);
  66     }
  67     
  68     public Macro(String name, String expansion, String signature)
  69         throws ValidationException {
  70         this();
  71         setKey(name);
  72         setValue(expansion, false, false);
  73         setSignature(signature);
  74     }
  75     
  76     public void setKey(String name) throws ValidationException {
  77         if (name.length() > MAX_NAME_SIZE) {
  78             Object [] args = new Object[1];
  79             args[0] = new Short(MAX_NAME_SIZE);
  80             MessageFormat form = new MessageFormat(
  81                 ResourceStrings.getString("macro_key_length"));
  82             String msg = form.format(args);
  83             throw new ValidationException(msg);
  84         }
  85         super.setKey(name);
  86     }
  87 
  88     public void setValue(String expansion, boolean edit, boolean validate)
  89         throws ValidationException {
  90 
  91         StringBuffer symbol = new StringBuffer();
  92         StringBuffer value = new StringBuffer();
  93         boolean inQuote = false;
  94         boolean inEscape = false;
  95         char c;
  96 
  97         // State list for parsing machine
  98         int START = 0;
  99         int NAME = 1;
 100         int VALUE = 2;
 101         int state = !edit ? START : NAME;
 102 
 103         for (int i = 0; i < expansion.length(); ++i) {
 104             c = expansion.charAt(i);
 105             if (!edit && (state == START)) {
 106                 // Start of expansion
 107                 if (c != ':' || expansion.length() == 1) {
 108                     Object [] args = new Object[1];
 109                     args[0] = getKey();
 110                     MessageFormat form = new MessageFormat(
 111                         ResourceStrings.getString("mac_syntax_error"));
 112                     String msg = form.format(args);
 113                     throw new ValidationException(msg);
 114                 }
 115                 state = NAME;
 116             } else if (state == NAME) {
 117                 // Name of symbol
 118                 if (c == '=') {
 119                     state = VALUE;
 120                 } else if (!edit && (c == ':')) {
 121                     if (!validate) {
 122                         storeOption(symbol.toString(), value.toString());
 123                     } else {
 124                         setOption(symbol.toString(), value.toString(), false);
 125                     }
 126                     symbol.setLength(0);
 127                     value.setLength(0);
 128                     state = NAME;                       
 129                 } else {
 130                     symbol.append(c);
 131                 }
 132             } else if (state == VALUE) {
 133                 // Value of symbol
 134                 if (inEscape) {
 135                     value.append(c);
 136                     inEscape = false;
 137                 } else if (c == '\\') {
 138                     inEscape = true;
 139                 } else if (c == '"') {
 140                     inQuote = !inQuote;
 141                     value.append(c);
 142                 } else if (inQuote) {
 143                     value.append(c);
 144                 } else if (!edit && (c == ':')) {
 145                     if (!validate) {
 146                         storeOption(symbol.toString(), value.toString());
 147                     } else {
 148                         setOption(symbol.toString(), value.toString(), false);
 149                     }
 150                     symbol.setLength(0);
 151                     value.setLength(0);
 152                     state = NAME;
 153                 } else {
 154                     value.append(c);
 155                 }
 156             }
 157         }
 158 
 159         if (edit) {
 160             setOption(symbol.toString(), value.toString(), true);
 161 
 162             valueClean = false;
 163         } else {
 164             if (state != NAME) {
 165                 Object [] args = new Object[1];
 166                 args[0] = getKey();
 167                 MessageFormat form = new MessageFormat(
 168                     ResourceStrings.getString("mac_syntax_error"));
 169                 String msg = form.format(args);
 170                 throw new ValidationException(msg);
 171             }
 172             super.setValue(expansion);
 173             valueClean = true;
 174         }
 175     }
 176 
 177     public void editOption(String expansion)
 178         throws ValidationException {
 179         setValue(expansion, true, false);
 180     } 
 181 
 182     /**
 183      * Common method used to set an option value for the macro.
 184      * @param symbol name of the option
 185      * @param value the option value(if any)
 186      * @param edit flag indicating that this is an edit of and existing option
 187      */
 188     private void setOption(String symbol, String value, boolean edit)
 189         throws ValidationException {
 190 
 191         int index = getOptionIndex(symbol);
 192 
 193         if (value.length() == 0) {
 194 
 195             if (edit) {
 196                 if (index == -1) {
 197                     Object [] args = new Object[1];
 198                     args[0] = symbol;
 199                     MessageFormat form = new MessageFormat(
 200                         ResourceStrings.getString("invalid_option"));
 201                     String msg = form.format(args);
 202                     throw new ValidationException(msg);
 203                 }
 204                 deleteOptionAt(index);
 205             } else {
 206                 OptionValue option = 
 207                     OptionValueFactory.newOptionValue(symbol, new String());
 208 
 209                 if (option instanceof BogusOptionValue) {
 210                     Object [] args = new Object[1];
 211                     args[0] = symbol;
 212                     MessageFormat form = new MessageFormat(
 213                         ResourceStrings.getString("invalid_option"));
 214                     String msg = form.format(args);
 215                     throw new ValidationException(msg);
 216                 } else if (!(option instanceof BooleanOptionValue)) {
 217                     Object [] args = new Object[1];
 218                     args[0] = symbol;
 219                     MessageFormat form = new MessageFormat(
 220                         ResourceStrings.getString("not_boolean_option"));
 221                     String msg = form.format(args);
 222                     throw new ValidationException(msg);
 223                 }
 224             }
 225 
 226         } else if (edit && value.equals(BOOLEAN_EDIT_VALUE)) {
 227 
 228             OptionValue option = 
 229                 OptionValueFactory.newOptionValue(symbol, new String());
 230 
 231             if (option instanceof BogusOptionValue) {
 232                 Object [] args = new Object[1];
 233                 args[0] = symbol;
 234                 MessageFormat form = new MessageFormat(
 235                     ResourceStrings.getString("invalid_option"));
 236                 String msg = form.format(args);
 237                 throw new ValidationException(msg);
 238             } else if (!(option instanceof BooleanOptionValue)) {
 239                 Object [] args = new Object[1];
 240                 args[0] = symbol;
 241                 MessageFormat form = new MessageFormat(
 242                     ResourceStrings.getString("not_boolean_option"));
 243                 String msg = form.format(args);
 244                 throw new ValidationException(msg);
 245             }
 246 
 247             if (index == -1) {
 248                 storeOption(option);
 249             } else {
 250                 // nothing to do - option already turned on
 251             }
 252 
 253         } else {
 254 
 255             OptionValue option = 
 256                 OptionValueFactory.newOptionValue(symbol);
 257             if (option instanceof BogusOptionValue) {
 258                 Object [] args = new Object[1];
 259                 args[0] = symbol;
 260                 MessageFormat form = new MessageFormat(
 261                     ResourceStrings.getString("invalid_option"));
 262                 String msg = form.format(args);
 263                 throw new ValidationException(msg);
 264             } else if (edit && option instanceof BooleanOptionValue) {
 265                 Object [] args = new Object[1];
 266                 args[0] = symbol;
 267                 MessageFormat form = new MessageFormat(
 268                     ResourceStrings.getString("boolean_option"));
 269                 String msg = form.format(args);
 270                 throw new ValidationException(msg);
 271             }
 272 
 273             if (index == -1) {
 274                 storeOption(option);
 275             } else {
 276                 option = getOptionAt(index);
 277             }
 278             option.setValue(value);
 279 
 280         }
 281     }
 282 
 283     public void storeOption(OptionValue option)
 284             throws ValidationException {
 285         options.addElement(option);
 286     }
 287 
 288     public void storeOption(String option, Object value)
 289             throws ValidationException {
 290         options.addElement(OptionValueFactory.newOptionValue(option, value));
 291     }
 292     
 293     // Useful for creating options when standard code values are known.
 294     //
 295     // XXX
 296     // NOTE!!! Do not use this method for now. We need to resolve whether or
 297     // not all standard options are going to have unique codes. Today, they do
 298     // not. We include internal options as standard and set their codes to 0.
 299     // 
 300     public void storeOption(int code, Object value) throws ValidationException {
 301         options.addElement(
 302             OptionValueFactory.newOptionValue(StandardOptions.nameForCode(code),
 303             value));
 304     }
 305 
 306     public String getValue() {
 307         boolean first;
 308         if (!valueClean) {
 309             // Construct a new value
 310             StringBuffer buf = new StringBuffer();
 311             for (Enumeration e = options.elements(); e.hasMoreElements(); ) {
 312                 OptionValue v = (OptionValue)e.nextElement();
 313                 if (v == null) {
 314                     continue;   // Ignore an empty position
 315                 }
 316                 buf.append(':');
 317                 buf.append(v.toString());
 318             }
 319             buf.append(':');
 320             try {
 321                 super.setValue(buf.toString());
 322             } catch (ValidationException ex) {
 323                 // Shouldn't happen; ignore it
 324             }
 325             valueClean = true;
 326         }
 327         return super.getValue();
 328     }
 329     
 330     public Enumeration elements() {
 331         return options.elements();
 332     }
 333     
 334     public OptionValue [] getOptions() {
 335         OptionValue [] optArray = new OptionValue[options.size()];
 336         options.copyInto(optArray);
 337         return optArray;
 338     }
 339     
 340     public OptionValue getOption(String name) {
 341         for (Enumeration en = options.elements(); en.hasMoreElements(); ) {
 342             OptionValue v = (OptionValue)en.nextElement();
 343             if (name.equals(v.getName())) {
 344                 return v;
 345             }
 346         }
 347         return null;
 348     }
 349     
 350     public int getOptionIndex(String name) {
 351         int index = -1;
 352         boolean found = false;
 353 
 354         Enumeration en = options.elements();
 355         while (en.hasMoreElements() && !found) {
 356             index++;
 357             OptionValue v = (OptionValue)en.nextElement();
 358             if (name.equals(v.getName())) {
 359                 found = true;
 360             }
 361         }
 362         if (!found) {
 363             index = -1;
 364         }
 365 
 366         return index;
 367     }
 368     
 369     public OptionValue getOptionAt(int index) {
 370         return (OptionValue)options.elementAt(index);
 371     }
 372     
 373     public void setOptionAt(OptionValue v, int index) {
 374         if (index >= options.size()) {
 375             options.setSize(index + 1); // Grow vector if necessary
 376         }
 377         options.setElementAt(v, index);
 378     }   
 379     
 380     public int optionCount() {
 381         return options.size();
 382     }
 383     
 384     public void deleteOptionAt(int index) {
 385         if (index >= options.size()) {
 386             return;
 387         }
 388         options.removeElementAt(index);
 389     }
 390     
 391     public void insertOptionAt(OptionValue v, int index) {
 392         options.insertElementAt(v, index);
 393     }
 394     
 395     // Make a copy of this macro
 396     public Object clone() {
 397         Macro m = new Macro();
 398         m.key = key;
 399         m.options = new Vector();
 400         for (Enumeration en = options.elements(); en.hasMoreElements(); ) {
 401             OptionValue v = (OptionValue)en.nextElement();
 402             m.options.addElement((OptionValue)v.clone());
 403         }
 404         m.signature = signature;
 405         return m;
 406     }
 407     
 408     public String toString() {
 409         return (getKey() + " m " + getValue());
 410     }
 411     
 412     // Verify that the options contained in this macro are all valid
 413     public void validate() throws ValidationException {
 414         for (Enumeration en = options.elements(); en.hasMoreElements(); ) {
 415             OptionValue v = (OptionValue)en.nextElement();
 416             if (!v.isValid()) {
 417                 throw new ValidationException(v.getName());
 418             }
 419         }
 420     }
 421 }