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 }