001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.vmutil.options;
014
015import org.vmmagic.pragma.Uninterruptible;
016import org.vmmagic.unboxed.*;
017
018/**
019 * The abstract base class for all option sets.
020 * <p>
021 * Concrete instantiations of this class include logic.
022 * <p>
023 * All options within the system should have a unique name. No
024 * two options shall have a name that is the same when a case
025 * insensitive comparison between the names with spaces removed
026 * is performed. Only basic alphanumeric characters and spaces
027 * are allowed.
028 * <p>
029 * The VM is required to provide a one way mapping function that
030 * takes the name and creates a VM style name, such as mapping
031 * "No Finalizer" to noFinalizer. The VM may not remove any letters
032 * when performing this mapping but may remove spaces and change
033 * the case of any character.
034 */
035public abstract class OptionSet {
036  private Option head;
037  private Option tail;
038  private final boolean loggingChanges;
039
040  /**
041   * Initialize the option set so that options can be created.
042   */
043  protected OptionSet() {
044    head = null;
045    tail = null;
046    loggingChanges = false;
047  }
048
049  /**
050   * Register the option to this set, computing its key in the process.
051   *
052   * @param o The option to register.
053   * @param name the option's name
054   * @return the computed key for the option
055   */
056  final String register(Option o, String name) {
057    if (tail == null) {
058      tail = head = o;
059    } else {
060      tail.setNext(o);
061      tail = o;
062    }
063    return computeKey(name);
064  }
065
066  /**
067   * Using the VM determined key, look up the corresponding option,
068   * or return <code>null</code> if an option can not be found.
069   *
070   * @param key The (unique) option key.
071   * @return The option, or <code>null</code>.
072   */
073  public final Option getOption(String key) {
074    Option o = getFirst();
075    while (o != null) {
076      if (o.getKey().equals(key)) {
077        return o;
078      }
079      o = o.getNext();
080    }
081    return null;
082  }
083
084  /**
085   * Return the first option. This can be used with the getNext method to
086   * iterate through the options.
087   *
088   * @return The first option, or <code>null</code> if no options exist.
089   */
090  public final Option getFirst() {
091    return head;
092  }
093
094  /**
095   * Log an option change
096   * @param o The option that changed
097   */
098  public void logChange(Option o) {
099    if (loggingChanges) {
100      logString("Option Update: ");
101      log(o);
102    }
103  }
104
105  /**
106   * Log the option value in plain text.
107   *
108   * @param o The option to log.
109   */
110  public void log(Option o) {
111    logString("Option '");
112    logString(o.getKey());
113    logString("' = ");
114    logValue(o, false);
115    logNewLine();
116  }
117
118  /**
119   * Log the option value in XML.
120   *
121   * @param o The option to log.
122   */
123  public void logXml(Option o) {
124    logString("<option name=\"");
125    logString(o.getKey());
126    logString("\" value=\"");
127    logValue(o, true);
128    logString("\"/>");
129    logNewLine();
130  }
131
132  /**
133   * Log the option values in XML.
134   */
135  public void logXml() {
136    logString("<options>");
137    logNewLine();
138
139    for (Option o = getFirst(); o != null; o = o.getNext()) {
140      logXml(o);
141    }
142
143    logString("</options>");
144    logNewLine();
145  }
146
147  /**
148   * Format and log an option value.
149   *
150   * @param o The option.
151   * @param forXml Is this part of XML output?
152   */
153  protected abstract void logValue(Option o, boolean forXml);
154
155  /**
156   * Log a string.
157   *
158   * @param s the string to log
159   */
160  protected abstract void logString(String s);
161
162  /**
163   * Print a new line.
164   */
165  protected abstract void logNewLine();
166
167  /**
168   * Determine the VM specific key for a given option name. Option names are
169   * space delimited with capitalised words (e.g. "GC Verbosity Level").
170   *
171   * @param name The option name.
172   * @return The VM specific key.
173   */
174  protected abstract String computeKey(String name);
175
176  /**
177   * A non-fatal error occurred during the setting of an option. This method
178   * calls into the VM and shall not cause the system to stop.
179   *
180   * @param o The responsible option.
181   * @param message The message associated with the warning.
182   */
183  protected abstract void warn(Option o, String message);
184
185  /**
186   * A fatal error occurred during the setting of an option. This method
187   * calls into the VM and is required to cause the system to stop.
188   *
189   * @param o The responsible option.
190   * @param message The error message associated with the failure.
191   */
192  protected abstract void fail(Option o, String message);
193
194  /**
195   * Convert bytes into pages, rounding up if necessary.
196   *
197   * @param bytes The number of bytes.
198   * @return The corresponding number of pages.
199   */
200  @Uninterruptible
201  protected abstract int bytesToPages(Extent bytes);
202
203  /**
204   * Convert from pages into bytes.
205   * @param pages the number of pages.
206   * @return The corresponding number of bytes.
207   */
208  @Uninterruptible
209  protected abstract Extent pagesToBytes(int pages);
210}
211