You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by sc...@apache.org on 2003/09/21 01:46:35 UTC

cvs commit: jakarta-commons-sandbox/primitives/src/codegen/org/apache/commons/primitive/iterator XXXIterator.vm

scolebourne    2003/09/20 16:46:35

  Added:       primitives/src/codegen/org/apache/commons/primitive
                        CodeGenerator.java
               primitives/src/codegen/org/apache/commons/primitive/collection
                        XXXCollection.vm
               primitives/src/codegen/org/apache/commons/primitive/listiterator
                        XXXListIterator.vm
               primitives/src/codegen/org/apache/commons/primitive/list
                        XXXList.vm
               primitives/src/codegen/org/apache/commons/primitive/iterator/impl
                        ArrayXXXIterator.vm
               primitives/src/codegen/org/apache/commons/primitive/iterator
                        XXXIterator.vm
  Log:
  Initial checkin of the primitives code generator
  
  Revision  Changes    Path
  1.1                  jakarta-commons-sandbox/primitives/src/codegen/org/apache/commons/primitive/CodeGenerator.java
  
  Index: CodeGenerator.java
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2003 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowledgement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgement may appear in the software itself,
   *    if and wherever such third-party acknowledgements normally appear.
   *
   * 4. The names "The Jakarta Project", "Commons", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   */
  package org.apache.commons.primitive;
  
  import java.io.BufferedReader;
  import java.io.FileReader;
  import java.io.FileWriter;
  import java.io.StringWriter;
  import java.util.HashMap;
  import java.util.Map;
  
  import org.apache.velocity.Template;
  import org.apache.velocity.VelocityContext;
  import org.apache.velocity.app.Velocity;
  
  /**
   * Generates the entire suite of classes.
   * 
   * @author Stephen Colebourne
   * @version $Id: CodeGenerator.java,v 1.1 2003/09/20 23:46:34 scolebourne Exp $
   * @since 1.0
   */
  public class CodeGenerator {
  
      /**
       * Main entry point to the code generator.
       * 
       * @param args
       */
      public static void main(String[] args) {
          if (args.length == 0) {
              args = TEMPLATE_FILENAMES;
          }
          try {
              System.out.println("Started");
              process(args);
              System.out.println("Finished");
          } catch (Throwable th) {
              th.printStackTrace();
          }
      }
      
      //-----------------------------------------------------------------------
      /**
       * Process all the templates.
       */
      private static void process(final String[] templateNames) throws Exception {
          Velocity.init();
          init();
          for (int i = 0; i < templateNames.length; i++) {
              process(templateNames[i]);
              System.out.print('.');
          }
          System.out.println();
      }
      
      //-----------------------------------------------------------------------
      /**
       * Initialize by reading the license.
       */
      private static void init() throws Exception {
          BufferedReader in = new BufferedReader(new FileReader("LICENSE.txt"));
          StringBuffer buf = new StringBuffer();
          String line = null;
          while ((line = in.readLine()) != null) {
              buf.append(line);
              buf.append(((char) 13));
              buf.append(((char) 10));
          }
          LICENSE = buf.substring(0, buf.length() - 2);
          in.close();
      }
      
      //-----------------------------------------------------------------------
      /**
       * Process a single template.
       */
      private static void process(final String templateName) throws Exception {
          final Template template = Velocity.getTemplate("src/codegen/" + templateName + ".vm");
          
          // init data
          for (int i = 0; i < TYPES.length; i++) {
              VelocityContext context = new VelocityContext(TYPES[i]);
              context.put("license", LICENSE);
          
              // merge
              StringWriter sw = new StringWriter();
              template.merge(context, sw);
          
              // create output filename
              String fileName = templateName + ".java";
              int pos = fileName.indexOf("XXX");
              if (pos >= 0) {
                  fileName = fileName.substring(0, pos) + context.get("Type") + fileName.substring(pos + 3);
              }
          
              // output
              FileWriter writer = new FileWriter("src/java/" + fileName);
              writer.write(sw.toString());
              writer.close();
          }
      }
  
      //-----------------------------------------------------------------------
      private static String LICENSE = "";
      
      private static final Map[] TYPES = new Map[] {
          new HashMap(), new HashMap(), new HashMap(), new HashMap(),
          new HashMap(), new HashMap(), new HashMap(), new HashMap()
      };
      
      static {
          TYPES[0].put("type", "long");
          TYPES[0].put("Type", "Long");
          TYPES[0].put("object", "Long");
          TYPES[0].put("preConvert", "new Long(");
          TYPES[0].put("postConvert", ")");
          
          TYPES[1].put("type", "int");
          TYPES[1].put("Type", "Int");
          TYPES[1].put("object", "Integer");
          TYPES[1].put("preConvert", "new Integer(");
          TYPES[1].put("postConvert", ")");
          
          TYPES[2].put("type", "short");
          TYPES[2].put("Type", "Short");
          TYPES[2].put("object", "Short");
          TYPES[2].put("preConvert", "new Short(");
          TYPES[2].put("postConvert", ")");
          
          TYPES[3].put("type", "byte");
          TYPES[3].put("Type", "Byte");
          TYPES[3].put("object", "Byte");
          TYPES[3].put("preConvert", "new Byte(");
          TYPES[3].put("postConvert", ")");
          
          TYPES[4].put("type", "double");
          TYPES[4].put("Type", "Double");
          TYPES[4].put("object", "Double");
          TYPES[4].put("preConvert", "new Double(");
          TYPES[4].put("postConvert", ")");
          
          TYPES[5].put("type", "float");
          TYPES[5].put("Type", "Float");
          TYPES[5].put("object", "Float");
          TYPES[5].put("preConvert", "new Float(");
          TYPES[5].put("postConvert", ")");
          
          TYPES[6].put("type", "char");
          TYPES[6].put("Type", "Char");
          TYPES[6].put("object", "Character");
          TYPES[6].put("preConvert", "new Character(");
          TYPES[6].put("postConvert", ")");
          
          TYPES[7].put("type", "boolean");
          TYPES[7].put("Type", "Boolean");
          TYPES[7].put("object", "Boolean");
          TYPES[7].put("preConvert", "(");
          TYPES[7].put("postConvert", " ? Boolean.TRUE : Boolean.FALSE)");
      }
  
      private static final String[] TEMPLATE_FILENAMES = new String[] {
          "org/apache/commons/primitive/collection/XXXCollection",
          "org/apache/commons/primitive/iterator/XXXIterator",
          "org/apache/commons/primitive/list/XXXList",
          "org/apache/commons/primitive/listiterator/XXXListIterator",
          
          "org/apache/commons/primitive/iterator/impl/ArrayXXXIterator"
      };
      
  }
  
  
  
  1.1                  jakarta-commons-sandbox/primitives/src/codegen/org/apache/commons/primitive/collection/XXXCollection.vm
  
  Index: XXXCollection.vm
  ===================================================================
  ${license}
  package org.apache.commons.primitive.collection;
  
  import java.util.Collection;
  
  import org.apache.commons.primitive.PrimitiveCollectable;
  import org.apache.commons.primitive.iterator.${Type}Iterator;
  
  /**
   * Defines a collection of primitive <code>${type}</code> values.
   * <p>
   * This interface extends {@link Collection} allowing seamless integration with other APIs.
   * All Collection methods can be used, using the primitive wrapper class {@link ${object}}.
   * However, it will be <em>much</em> more efficient to use the methods defined here.
   * 
   * @author Stephen Colebourne
   * @version $Id: XXXCollection.vm,v 1.1 2003/09/20 23:46:34 scolebourne Exp $
   * @since 1.0
   */
  public interface ${Type}Collection extends PrimitiveCollectable, Collection {
      // This file is CODE GENERATED. Do not change manually.
  
      // Mandatory operations
      //-----------------------------------------------------------------------
      /**
       * Gets an iterator over this collection.
       *
       * @return an iterator over this collection
       */
      ${Type}Iterator valueIterator();
  
      /**
       * Checks whether this collection contains a specified primitive value.
       *
       * @param value  the value to search for
       * @return <code>true</code> if the value is found
       */
      boolean containsValue(${type} value);
  
      /**
       * Checks if the collection contains all of the primitive values (optional operation).
       *
       * @param values  the values to search for
       * @return <code>true</code> if all the values are found
       */
      boolean containsAllValues(${type}[] values);
  
      /**
       * Gets the elements of this collection as an array.
       *
       * @return a new array containing a copy of the elements of this collection
       */
      ${type}[] toValueArray();
  
      /**
       * Copies the elements of this collection into an array at a specified position.
       * <p>
       * If the array specified is large enough, it will be modified.
       * If the array is not large enough, a new array will be created and all
       * elements copied before the insertion begins.
       *
       * @param array  the array to add the elements to
       * @param insertionIndex  the position in the array to add the elements to
       * @return the array with the inserted collection
       * @throws IndexOutOfBoundsException if the index is invalid
       */
      ${type}[] toValueArray(${type}[] array, int insertionIndex);
  
      // Optional operations
      //-----------------------------------------------------------------------
      /**
       * Adds a primitive value to this collection (optional operation).
       * <p>
       * This method is optional, throwing an UnsupportedOperationException if the
       * collection cannot be added to.
       *
       * @param value  the value to add to this collection
       * @return <code>true</code> if this collection was modified by this method call
       * @throws IllegalArgumentException if value is rejected by this collection
       * @throws UnsupportedOperationException if not supported by this collection
       */
      boolean addValue(${type} value);
  
      /**
       * Removes the first occurrance of the specified primitive value from
       * this collection (optional operation).
       * <p>
       * This method is optional, throwing an UnsupportedOperationException if the
       * collection cannot be removed from.
       *
       * @param value  the value to remove
       * @return <code>true</code> if this collection was modified by this method call
       * @throws UnsupportedOperationException if not supported by this collection
       */
      boolean removeValue(${type} value);
  
      /**
       * Adds an array of primitive values to this list (optional operation).
       * <p>
       * This method is optional, throwing an UnsupportedOperationException if the
       * collection cannot be added to.
       *
       * @param values  the values to add to this collection
       * @return <code>true</code> if this list was modified by this method call
       * @throws IllegalArgumentException if value is rejected by this collection
       * @throws UnsupportedOperationException if not supported by this collection
       */
      boolean addAllValues(${type}[] values);
  
      /**
       * Removes each of an array of primitive values from this list (optional operation).
       * <p>
       * This method is optional, throwing an UnsupportedOperationException if the
       * collection cannot be added to.
       *
       * @param values  the values to remove from this collection
       * @return <code>true</code> if this list was modified by this method call
       * @throws UnsupportedOperationException if not supported by this collection
       */
      boolean removeAllValues(${type}[] values);
  
  }
  
  
  
  1.1                  jakarta-commons-sandbox/primitives/src/codegen/org/apache/commons/primitive/listiterator/XXXListIterator.vm
  
  Index: XXXListIterator.vm
  ===================================================================
  ${license}
  package org.apache.commons.primitive.listiterator;
  
  /**
   * Defines a list iterator over primitive <code>${type}</code> values.
   * 
   * @author Stephen Colebourne
   * @version $Id: XXXListIterator.vm,v 1.1 2003/09/20 23:46:34 scolebourne Exp $
   * @since 1.0
   */
  public interface ${Type}ListIterator extends PrimitiveListIterator {
      // This file is CODE GENERATED. Do not change manually.
  
      // Mandatory operations
      //-----------------------------------------------------------------------
      /**
       * Gets the previous value from the iterator.
       *
       * @return the previous available value
       * @throws NoSuchElementException if there are no more values available
       */
      ${type} previousValue();
  
      // Optional operations
      //-----------------------------------------------------------------------
      /**
       * Adds the specified value to the list underlying the iterator at the
       * current iteration index.
       *
       * @param value  the value to add
       * @throws IllegalStateException if the iterator cannot be added to at present
       * @throws UnsupportedOperationException if not supported by this collection
       */
      void addValue(${type} value);
  
      /**
       * Sets the last retrieved value from the iterator.
       *
       * @param value  the value to set
       * @throws IllegalStateException if the iterator cannot be set to at present
       * @throws UnsupportedOperationException if not supported by this collection
       */
      int setValue(${type} value);
  
  }
  
  
  
  1.1                  jakarta-commons-sandbox/primitives/src/codegen/org/apache/commons/primitive/list/XXXList.vm
  
  Index: XXXList.vm
  ===================================================================
  ${license}
  package org.apache.commons.primitive.list;
  
  import org.apache.commons.primitive.collection.${Type}Collection;
  import org.apache.commons.primitive.listiterator.${Type}ListIterator;
  
  /**
   * Defines a list of primitive <code>${type}</code> values.
   * <p>
   * This interface extends {@link List} allowing seamless integration with other APIs.
   * All List methods can be used, using the primitive wrapper class {@link ${object}}.
   * However, it will be <em>much</em> more efficient to use the methods defined here.
   * 
   * @author Stephen Colebourne
   * @version $Id: XXXList.vm,v 1.1 2003/09/20 23:46:34 scolebourne Exp $
   * @since 1.0
   */
  public interface ${Type}List extends PrimitiveList, ${Type}Collection {
      // This file is CODE GENERATED. Do not change manually.
  
      // Mandatory operations
      //-----------------------------------------------------------------------
      /**
       * Gets the primitive value at the specified index.
       *
       * @param index  the index to get from
       * @return value at the index
       * @throws IndexOutOfBoundsException if the index is invalid
       */
      ${type} getValue(int index);
  
      /**
       * Gets the first primitive value.
       *
       * @return value at index zero
       * @throws IndexOutOfBoundsException if the index is invalid
       */
      ${type} firstValue();
  
      /**
       * Gets the last primitive value.
       *
       * @return value at index <code>size() - 1</code>
       * @throws IndexOutOfBoundsException if the index is invalid
       */
      ${type} lastValue();
  
      /**
       * Gets a list iterator over this list.
       *
       * @return an iterator over this list
       */
      ${Type}ListIterator valueListIterator();
  
      /**
       * Gets a list iterator over this list from a start index.
       *
       * @param index  the index to start from
       * @return an iterator over this list
       * @throws IndexOutOfBoundsException if the index is invalid
       */
      ${Type}ListIterator valueListIterator(int index);
  
      /**
       * Gets the first index of the specified primitive value.
       *
       * @param value  the value to search for
       * @return the zero-based index, or <code>-1</code> if not found
       */
      int indexOfValue(${type} value);
  
      /**
       * Gets the first index of the specified primitive value from an index.
       * <p>
       * This method follows the conventions of <code>String</code> in that a
       * negative index is treated as zero, and an index greater than the list
       * size will simply return <code>-1</code>.
       *
       * @param value  the value to search for
       * @param fromIndexInclusive  the index to start searching from, inclusive
       * @return the zero-based index, or <code>-1</code> if not found
       */
      int indexOfValue(${type} value, int fromIndexInclusive);
  
      /**
       * Gets the last index of the specified primitive value.
       *
       * @param value  the value to search for
       * @return the zero-based index, or <code>-1</code> if not found
       */
      int lastIndexOfValue(${type} value);
  
      /**
       * Gets the first index of the specified primitive value from an index.
       * <p>
       * This method follows the conventions of <code>String</code> in that an
       * index greater than the list size will start searching at the list size,
       * and a negative index simply returns <code>-1</code>.
       *
       * @param value  the value to search for
       * @param fromIndexInclusive  the index to start searching from, inclusive
       * @return the zero-based index, or <code>-1</code> if not found
       */
      int lastIndexOfValue(${type} value, int fromIndexInclusive);
  
      /**
       * Gets a range of elements as an array.
       *
       * @param fromIndexInclusive  the index to start from, inclusive
       * @param toIndexExclusive  the index to end at, exclusive
       * @return a new array containing a copy of the range of elements
       * @throws IndexOutOfBoundsException if either index is invalid
       */
      ${type}[] toValueArray(int fromIndexInclusive, int toIndexExclusive);
  
      /**
       * Copies a range of elements into an array at a specified position.
       * <p>
       * If the array specified is large enough, it will be modified.
       * If the array is not large enough, a new array will be created and all
       * elements copied before the insertion begins.
       *
       * @param fromIndexInclusive  the index to start from, inclusive
       * @param toIndexExclusive  the index to end at, exclusive
       * @param array  the array to add the elements to
       * @param insertionIndex  the position in the array to add the elements to
       * @return the array with the inserted collection
       * @throws IndexOutOfBoundsException if any index is invalid
       */
      ${type}[] toValueArray(int fromIndexInclusive, int toIndexExclusive, ${type}[] array, int insertionIndex);
  
      /**
       * Sets the primitive values starting at a specified index.
       * <p>
       * This method is optional, throwing an UnsupportedOperationException if the
       * collection cannot be changed.
       *
       * @param fromIndexInclusive  the index to start from, inclusive
       * @param toIndexExclusive  the index to end at, exclusive
       * @return a new ${Type}List for the subList
       * @throws IndexOutOfBoundsException if either index is invalid
       */
      ${Type}List valueSubList(int fromIndexInclusive, int toIndexExclusive);
  
      // Optional operations
      //-----------------------------------------------------------------------
      /**
       * Adds a primitive value to this list at an index (optional operation).
       * <p>
       * This method is optional, throwing an UnsupportedOperationException if the
       * collection cannot be added to.
       *
       * @param index  the index to add at
       * @param value  the value to add to this collection
       * @return <code>true</code> if this list was modified by this method call
       * @throws IndexOutOfBoundsException if the index is invalid
       * @throws IllegalArgumentException if value is rejected by this collection
       * @throws UnsupportedOperationException if not supported by this collection
       */
      boolean addValue(int index, ${type} value);
  
      /**
       * Adds an array of primitive values to this list at an index (optional operation).
       * <p>
       * This method is optional, throwing an UnsupportedOperationException if the
       * collection cannot be added to.
       *
       * @param index  the index to add at
       * @param values  the values to add to this collection
       * @return <code>true</code> if this list was modified by this method call
       * @throws IndexOutOfBoundsException if the index is invalid
       * @throws IllegalArgumentException if value is rejected by this collection
       * @throws UnsupportedOperationException if not supported by this collection
       */
      boolean addAllValues(int index, ${type}[] values);
  
      /**
       * Sets the primitive value at a specified index.
       * <p>
       * This method is optional, throwing an UnsupportedOperationException if the
       * collection cannot be changed.
       *
       * @param index  the index to set
       * @param value  the value to store
       * @return the previous value at the index
       * @throws IndexOutOfBoundsException if the index is invalid
       * @throws IllegalArgumentException if value is rejected by this collection
       * @throws UnsupportedOperationException if not supported by this collection
       */
      ${type} setValue(int index, ${type} value);
  
      /**
       * Sets the primitive values starting at a specified index.
       * <p>
       * This method is optional, throwing an UnsupportedOperationException if the
       * collection cannot be changed.
       *
       * @param index  the index to start setting at
       * @param values  the values to store
       * @return <code>true</code> if this list was modified by this method call
       * @throws IndexOutOfBoundsException if the index is invalid
       * @throws IllegalArgumentException if value is rejected by this collection
       * @throws UnsupportedOperationException if not supported by this collection
       */
      boolean setAllValues(int index, ${type}[] values);
  
  }
  
  
  
  1.1                  jakarta-commons-sandbox/primitives/src/codegen/org/apache/commons/primitive/iterator/impl/ArrayXXXIterator.vm
  
  Index: ArrayXXXIterator.vm
  ===================================================================
  ${license}
  package org.apache.commons.primitive.iterator.impl;
  
  import java.util.NoSuchElementException;
  
  import org.apache.commons.primitive.iterator.${Type}Iterator;
  
  /**
   * An iterator over an array of <code>${type}</code> values.
   * <p>
   * The iterator can be reset to the start if required.
   * It is unmodifiable and <code>remove()</code> is unsupported.
   *
   * @author Stephen Colebourne
   * @version $Id: ArrayXXXIterator.vm,v 1.1 2003/09/20 23:46:34 scolebourne Exp $
   * @since 1.0
   */
  public class Array${Type}Iterator implements ${Type}Iterator {
      // This file is CODE GENERATED. Do not change manually.
      
      /** The array to iterate over */
      protected final ${type}[] array;
      /** Cursor position */
      protected int cursor = 0;
      
      /**
       * Constructs an iterator over an <code>${type}</code> array.
       * 
       * @param array  the array to iterate over, must not be null
       * @throws IllegalArgumentException if the array is null
       */
      public Array${Type}Iterator(${type}[] array) {
          super();
          if (array == null) {
              throw new IllegalArgumentException("Array must not be null");
          }
          this.array = array;
      }
  
      //-----------------------------------------------------------------------
      public boolean isModifiable() {
          return false;
      }
      
      public boolean isResetable() {
          return true;
      }
      
      //-----------------------------------------------------------------------
      public boolean hasNext() {
          return (cursor < array.length);
      }
  
      public ${type} nextValue() {
          if (hasNext() == false) {
              throw new NoSuchElementException("There are no more elements in this iterator");
          }
          return array[cursor++];
      }
  
      public Object next() {
          return ${preConvert}nextValue()${postConvert};
      }
  
      public void remove() {
          throw new UnsupportedOperationException("Array${Type}Iterator does not support remove");
      }
  
      public void reset() {
          cursor = 0;
      }
  
  }
  
  
  
  1.1                  jakarta-commons-sandbox/primitives/src/codegen/org/apache/commons/primitive/iterator/XXXIterator.vm
  
  Index: XXXIterator.vm
  ===================================================================
  ${license}
  package org.apache.commons.primitive.iterator;
  
  /**
   * Defines an iterator over primitive <code>${type}</code> values.
   * 
   * @author Stephen Colebourne
   * @version $Id: XXXIterator.vm,v 1.1 2003/09/20 23:46:34 scolebourne Exp $
   * @since 1.0
   */
  public interface ${Type}Iterator extends PrimitiveIterator {
      // This file is CODE GENERATED. Do not change manually.
  
      // Mandatory operations
      //-----------------------------------------------------------------------
      /**
       * Gets the next value from the iterator
       *
       * @return the next available value
       * @throws NoSuchElementException if there are no more values available
       */
      ${type} nextValue();
  
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org