View Javadoc

    1   /*
    2    * $Id: GString.java,v 1.16 2005/11/04 08:33:57 tug Exp $
    3    *
    4    * Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
    5    *
    6    * Redistribution and use of this software and associated documentation
    7    * ("Software"), with or without modification, are permitted provided that the
    8    * following conditions are met: 1. Redistributions of source code must retain
    9    * copyright statements and notices. Redistributions must also contain a copy
    10   * of this document. 2. Redistributions in binary form must reproduce the above
    11   * copyright notice, this list of conditions and the following disclaimer in
    12   * the documentation and/or other materials provided with the distribution. 3.
    13   * The name "groovy" must not be used to endorse or promote products derived
    14   * from this Software without prior written permission of The Codehaus. For
    15   * written permission, please contact info@codehaus.org. 4. Products derived
    16   * from this Software may not be called "groovy" nor may "groovy" appear in
    17   * their names without prior written permission of The Codehaus. "groovy" is a
    18   * registered trademark of The Codehaus. 5. Due credit should be given to The
    19   * Codehaus - http://groovy.codehaus.org/
    20   *
    21   * THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
    22   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    23   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    24   * DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
    25   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    26   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    27   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    28   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    29   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    30   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
    31   * DAMAGE.
    32   *
    33   */
    34  package groovy.lang;
    35
    36  import java.io.IOException;
    37  import java.io.StringWriter;
    38  import java.io.Writer;
    39  import java.util.ArrayList;
    40  import java.util.Arrays;
    41  import java.util.List;
    42  import java.util.regex.Pattern;
    43
    44  import org.codehaus.groovy.runtime.InvokerHelper;
    45
    46  /***
    47   * Represents a String which contains embedded values such as "hello there
    48   * ${user} how are you?" which can be evaluated lazily. Advanced users can
    49   * iterate over the text and values to perform special processing, such as for
    50   * performing SQL operations, the values can be substituted for ? and the
    51   * actual value objects can be bound to a JDBC statement. The lovely name of
    52   * this class was suggested by Jules Gosnell and was such a good idea, I
    53   * couldn't resist :)
    54   *
    55   * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
    56   * @version $Revision: 1.16 $
    57   */
    58  public abstract class GString extends GroovyObjectSupport implements Comparable, CharSequence, Writable, Buildable {
    59
    60      private Object[] values;
    61
    62      public GString(Object values) {
    63          this.values = (Object[]) values;
    64      }
    65
    66      public GString(Object[] values) {
    67          this.values = values;
    68      }
    69
    70      // will be static in an instance
    71      public abstract String[] getStrings();
    72
    73      /***
    74       * Overloaded to implement duck typing for Strings
    75       * so that any method that can't be evaluated on this
    76       * object will be forwarded to the toString() object instead.
    77       */
    78      public Object invokeMethod(String name, Object args) {
    79          try {
    80              return super.invokeMethod(name, args);
    81          }
    82          catch (MissingMethodException e) {
    83              // lets try invoke the method on the real String
    84              return InvokerHelper.invokeMethod(toString(), name, args);
    85          }
    86      }
    87
    88      public Object[] getValues() {
    89          return values;
    90      }
    91
    92      public GString plus(GString that) {
    93          List stringList = new ArrayList();
    94          List valueList = new ArrayList();
    95
    96          stringList.addAll(Arrays.asList(getStrings()));
    97          valueList.addAll(Arrays.asList(getValues()));
    98
    99          if (stringList.size() > valueList.size()) {
    100             valueList.add("");
    101         }
    102
    103         stringList.addAll(Arrays.asList(that.getStrings()));
    104         valueList.addAll(Arrays.asList(that.getValues()));
    105
    106         final String[] newStrings = new String[stringList.size()];
    107         stringList.toArray(newStrings);
    108         Object[] newValues = valueList.toArray();
    109
    110         return new GString(newValues) {
    111             public String[] getStrings() {
    112                 return newStrings;
    113             }
    114         };
    115     }
    116
    117     public GString plus(String that) {
    118         String[] currentStrings = getStrings();
    119         String[] newStrings = null;
    120         Object[] newValues = null;
    121
    122         newStrings = new String[currentStrings.length + 1];
    123         newValues = new Object[getValues().length + 1];
    124         int lastIndex = currentStrings.length;
    125         System.arraycopy(currentStrings, 0, newStrings, 0, lastIndex);
    126         System.arraycopy(getValues(), 0, newValues, 0, getValues().length);
    127         newStrings[lastIndex] = that;
    128         newValues[getValues().length] = "";
    129
    130         final String[] finalStrings = newStrings;
    131         return new GString(newValues) {
    132
    133             public String[] getStrings() {
    134                 return finalStrings;
    135             }
    136         };
    137     }
    138
    139     public int getValueCount() {
    140         return values.length;
    141     }
    142
    143     public Object getValue(int idx) {
    144         return values[idx];
    145     }
    146
    147     public String toString() {
    148         StringWriter buffer = new StringWriter();
    149         try {
    150             writeTo(buffer);
    151         }
    152         catch (IOException e) {
    153             throw new StringWriterIOException(e);
    154         }
    155         return buffer.toString();
    156     }
    157
    158     public Writer writeTo(Writer out) throws IOException {
    159         String[] s = getStrings();
    160         int numberOfValues = values.length;
    161         for (int i = 0, size = s.length; i < size; i++) {
    162             out.write(s[i]);
    163             if (i < numberOfValues) {
    164                 InvokerHelper.write(out, values[i]);
    165             }
    166         }
    167         return out;
    168     }
    169
    170     /* (non-Javadoc)
    171      * @see groovy.lang.Buildable#build(groovy.lang.GroovyObject)
    172      */
    173     public void build(final GroovyObject builder) {
    174     final String[] s = getStrings();
    175     final int numberOfValues = values.length;
    176
    177         for (int i = 0, size = s.length; i < size; i++) {
    178             builder.getProperty("mkp");
    179             builder.invokeMethod("yield", new Object[]{s[i]});
    180             if (i < numberOfValues) {
    181                 builder.getProperty("mkp");
    182                 builder.invokeMethod("yield", new Object[]{values[i]});
    183             }
    184         }
    185     }
    186
    187     public boolean equals(Object that) {
    188         if (that instanceof GString) {
    189             return equals((GString) that);
    190         }
    191         return false;
    192     }
    193
    194     public boolean equals(GString that) {
    195         return toString().equals(that.toString());
    196     }
    197
    198     public int hashCode() {
    199         return 37 + toString().hashCode();
    200     }
    201
    202     public int compareTo(Object that) {
    203         return toString().compareTo(that.toString());
    204     }
    205
    206     public char charAt(int index) {
    207         return toString().charAt(index);
    208     }
    209
    210     public int length() {
    211         return toString().length();
    212     }
    213
    214     public CharSequence subSequence(int start, int end) {
    215         return toString().subSequence(start, end);
    216     }
    217
    218     /***
    219      * Turns a String into a regular expression pattern
    220      *
    221      * @return the regular expression pattern
    222      */
    223     public Pattern negate() {
    224         return InvokerHelper.regexPattern(toString());
    225     }
    226 }