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     */
013    package org.vmutil.options;
014    
015    import org.vmmagic.pragma.Uninterruptible;
016    import 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     */
035    public abstract class OptionSet {
036      private Option head;
037      private Option tail;
038      private 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       */
054      final String register(Option o, String name) {
055        if (tail == null) {
056          tail = head = o;
057        } else {
058          tail.setNext(o);
059          tail = o;
060        }
061        return computeKey(name);
062      }
063    
064      /**
065       * Using the VM determined key, look up the corresponding option,
066       * or return <code>null</code> if an option can not be found.
067       *
068       * @param key The (unique) option key.
069       * @return The option, or <code>null</code>.
070       */
071      public final Option getOption(String key) {
072        Option o = getFirst();
073        while (o != null) {
074          if (o.getKey().equals(key)) {
075            return o;
076          }
077          o = o.getNext();
078        }
079        return null;
080      }
081    
082      /**
083       * Return the first option. This can be used with the getNext method to
084       * iterate through the options.
085       *
086       * @return The first option, or <code>null</code> if no options exist.
087       */
088      public final Option getFirst() {
089        return head;
090      }
091    
092      /**
093       * Log an option change
094       * @param o The option that changed
095       */
096      public void logChange(Option o) {
097        if (loggingChanges) {
098          logString("Option Update: ");
099          log(o);
100        }
101      }
102    
103      /**
104       * Log the option value in plain text.
105       *
106       * @param o The option to log.
107       */
108      public void log(Option o) {
109        logString("Option '");
110        logString(o.getKey());
111        logString("' = ");
112        logValue(o, false);
113        logNewLine();
114      }
115    
116      /**
117       * Log the option value in XML.
118       *
119       * @param o The option to log.
120       */
121      public void logXml(Option o) {
122        logString("<option name=\"");
123        logString(o.getKey());
124        logString("\" value=\"");
125        logValue(o, true);
126        logString("\"/>");
127        logNewLine();
128      }
129    
130      /**
131       * Log the option values in XML.
132       */
133      public void logXml() {
134        logString("<options>");
135        logNewLine();
136    
137        for(Option o = getFirst(); o != null; o = o.getNext()) {
138          logXml(o);
139        }
140    
141        logString("</options>");
142        logNewLine();
143      }
144    
145      /**
146       * Format and log an option value.
147       *
148       * @param o The option.
149       * @param forXml Is this part of XML output?
150       */
151      protected abstract void logValue(Option o, boolean forXml);
152    
153      /**
154       * Log a string.
155       */
156      protected abstract void logString(String s);
157    
158      /**
159       * Print a new line.
160       */
161      protected abstract void logNewLine();
162    
163      /**
164       * Determine the VM specific key for a given option name. Option names are
165       * space delimited with capitalised words (e.g. "GC Verbosity Level").
166       *
167       * @param name The option name.
168       * @return The VM specific key.
169       */
170      protected abstract String computeKey(String name);
171    
172      /**
173       * A non-fatal error occurred during the setting of an option. This method
174       * calls into the VM and shall not cause the system to stop.
175       *
176       * @param o The responsible option.
177       * @param message The message associated with the warning.
178       */
179      protected abstract void warn(Option o, String message);
180    
181      /**
182       * A fatal error occurred during the setting of an option. This method
183       * calls into the VM and is required to cause the system to stop.
184       *
185       * @param o The responsible option.
186       * @param message The error message associated with the failure.
187       */
188      protected abstract void fail(Option o, String message);
189    
190      /**
191       * Convert bytes into pages, rounding up if necessary.
192       *
193       * @param bytes The number of bytes.
194       * @return The corresponding number of pages.
195       */
196      @Uninterruptible
197      protected abstract int bytesToPages(Extent bytes);
198    
199      /**
200       * Convert from pages into bytes.
201       * @param pages the number of pages.
202       * @return The corresponding number of bytes.
203       */
204      @Uninterruptible
205      protected abstract Extent pagesToBytes(int pages);
206    }
207