001package com.avaje.ebean.config;
002
003/**
004 * Converts between Camel Case and Underscore based names for both table and
005 * column names (and is the default naming convention in Ebean).
006 *
007 * @author emcgreal
008 * @author rbygrave
009 */
010public class UnderscoreNamingConvention extends AbstractNamingConvention {
011
012  /**
013   * Force toUnderscore to return in upper case.
014   */
015  private boolean forceUpperCase = false;
016
017  /**
018   * The digits compressed.
019   */
020  private boolean digitsCompressed = true;
021
022  /**
023   * Create with a given sequence format.
024   *
025   * @param sequenceFormat the sequence format
026   */
027  public UnderscoreNamingConvention(String sequenceFormat) {
028    super(sequenceFormat);
029  }
030
031  /**
032   * Create with a sequence format of "{table}_seq".
033   */
034  public UnderscoreNamingConvention() {
035    super();
036  }
037
038  /**
039   * Returns the last part of the class name.
040   *
041   * @param beanClass the bean class
042   * @return the table name from class
043   */
044  public TableName getTableNameByConvention(Class<?> beanClass) {
045
046    return new TableName(getCatalog(), getSchema(), toUnderscoreFromCamel(beanClass.getSimpleName()));
047  }
048
049  /**
050   * Converts Camel case property name to underscore based column name.
051   *
052   * @return the column from property
053   */
054  public String getColumnFromProperty(Class<?> beanClass, String propertyName) {
055
056    return toUnderscoreFromCamel(propertyName);
057  }
058
059  /**
060   * Converts underscore based column name to Camel case property name.
061   *
062   * @param beanClass    the bean class
063   * @param dbColumnName the db column name
064   * @return the property from column
065   */
066  public String getPropertyFromColumn(Class<?> beanClass, String dbColumnName) {
067    return toCamelFromUnderscore(dbColumnName);
068  }
069
070  /**
071   * Return true if the result will be upper case.
072   * <p>
073   * False if it will be lower case.
074   * </p>
075   */
076  public boolean isForceUpperCase() {
077    return forceUpperCase;
078  }
079
080  /**
081   * Set to true to make the result upper case.
082   */
083  public void setForceUpperCase(boolean forceUpperCase) {
084    this.forceUpperCase = forceUpperCase;
085  }
086
087  /**
088   * Returns true if digits are compressed.
089   */
090  public boolean isDigitsCompressed() {
091    return digitsCompressed;
092  }
093
094  /**
095   * Sets to true for digits to be compressed (without a leading underscore).
096   */
097  public void setDigitsCompressed(boolean digitsCompressed) {
098    this.digitsCompressed = digitsCompressed;
099  }
100
101  /**
102   * Convert and return the string to underscore from camel case.
103   */
104  protected String toUnderscoreFromCamel(String camelCase) {
105
106    int lastUpper = -1;
107    StringBuilder sb = new StringBuilder(camelCase.length()+4);
108    for (int i = 0; i < camelCase.length(); i++) {
109      char c = camelCase.charAt(i);
110
111      if ('_' == c) {
112        // Underscores should just be passed through
113        sb.append(c);
114        lastUpper = i;
115      } else if (Character.isDigit(c)) {
116        if (i > lastUpper + 1 && !digitsCompressed) {
117          sb.append("_");
118        }
119        sb.append(c);
120        lastUpper = i;
121
122      } else if (Character.isUpperCase(c)) {
123        if (i > lastUpper + 1) {
124          sb.append("_");
125        }
126        sb.append(Character.toLowerCase(c));
127        lastUpper = i;
128
129      } else {
130        sb.append(c);
131      }
132    }
133    String ret = sb.toString();
134    if (forceUpperCase) {
135      ret = ret.toUpperCase();
136    }
137    return ret;
138  }
139
140  /**
141   * Convert and return the from string from underscore to camel case.
142   */
143  protected String toCamelFromUnderscore(String underscore) {
144
145    StringBuilder result = new StringBuilder(underscore.length());
146    String[] vals = underscore.split("_");
147
148    for (int i = 0; i < vals.length; i++) {
149      String lower = vals[i].toLowerCase();
150      if (i > 0) {
151        char c = Character.toUpperCase(lower.charAt(0));
152        result.append(c);
153        result.append(lower.substring(1));
154      } else {
155        result.append(lower);
156      }
157    }
158
159    return result.toString();
160  }
161}