TableDefinition.java :  » Plugin » sqlitegen » com » antlersoft » android » dbgen » Android Open Source

Android Open Source » Plugin » sqlitegen 
sqlitegen » com » antlersoft » android » dbgen » TableDefinition.java
/**
 * Copyright (C) 2008 Michael A. MacDonald
 */
package com.antlersoft.android.dbgen;

import java.io.PrintWriter;
import java.text.MessageFormat;
import java.util.ArrayList;

import com.antlersoft.android.db.FieldType;
import com.antlersoft.android.db.FieldVisibility;

import com.antlersoft.classwriter.TypeParse;

/**
 * Table properties as defined by annotations on interface class
 * @author Michael A. MacDonald
 *
 */
class TableDefinition {
  String packageName;
  String name;
  String implementingClass;
  String interfaceName;
  boolean makeAbstract;
  boolean makePublic;
  
  ArrayList<FieldDefinition> fieldDefinitions;
  
  TableDefinition(String name)
  {
    this.name=name;
    fieldDefinitions=new ArrayList<FieldDefinition>();
  }
  
  TableDefinition()
  {
    this("");
  }
  
  class Indenter
  {
    private PrintWriter pw;
    int indentation;
    /** True if last printed was a new line */
    private boolean endOfLine;
    
    Indenter(PrintWriter pw) {
      this.pw=pw;
      endOfLine=true;
    }
    
    void indent()
    {
      if ( ! endOfLine) {
        pw.println();
      }
      for ( int i=0; i<indentation; ++i)
      {
        pw.print("    ");
      }
      endOfLine=false;
    }

    /** Print a closing brace, adjusting indentation */
    void closeBrace()
    {
      indentation--;
      indent();
      pw.println("}");
      endOfLine=true;
    }
    
    /**
     * Print a line with indentation; adjust indentation for opening brace
     */
    void iprintln(String line)
    {
      indent();
      pw.println(line);
      endOfLine=true;
      if ( line.endsWith("{")) {
        indentation++;
      }
    }
    
    /**
     * Print a line with indentation, prepending public if makePublic flag true
     * @param line
     */
    void ivprintln(String line)
    {
      indent();
      if ( makePublic ) { pw.print("public "); }
      pw.println(line);
      endOfLine=true;
      if ( line.endsWith("{")) {
        indentation++;
      }
    }
    
    void nl() {
      if ( ! endOfLine)
        pw.println();
      pw.println();
    }
  }

  private static String TABLE_NAME_SYMBOL = "GEN_TABLE_NAME";
  private static String FIELD_COUNT_SYMBOL = "GEN_COUNT";
  
  private static String idSymbol(FieldDefinition fd)
  {
    return "GEN_ID_"+fd.columnName.toUpperCase();
  }
  
  private static String nameSymbol(FieldDefinition fd)
  {
    return "GEN_FIELD_"+fd.columnName.toUpperCase();
  }
  
  private static String getObjectType(FieldDefinition fd) {
    String objectType = fd.javaType.substring(0,1).toUpperCase()+fd.javaType.substring(1);
    if ( objectType.equals("Int")) objectType="Integer";
    return objectType;
  }
  
  private boolean hasId()
  {
    for (FieldDefinition fd : fieldDefinitions)
    {
      if (fd.columnName.equals("_id") && fd.javaType.equals("long"))
        return true;
    }
    return false;
  }
  
  /**
   * Escape a string so it can appear within Oracle single quotes
   * @param f string to escape
   * @return string with any ' characters doubled
   */
  private static String escapeDBString(String f)
  {
    StringBuilder b=new StringBuilder();
    int l = f.length();
    for (int i=0; i<l; i++)
    {
      char c = f.charAt(i);
      if (c == '\'')
      {
        b.append(c);
      }
      b.append(c);
    }
    return b.toString();
  }
  
  /**
   * Escape a string so it can appear within a double quoted string in Java source code
   * @param f string to escape
   * @return string with any " characters doubled and control characters converted to
   * octal escapes
   */
  private static String escapeJavaString(String f)
  {
    StringBuilder b=new StringBuilder();
    int l = f.length();
    for (int i=0; i<l; i++)
    {
      char c = f.charAt(i);
      if (c=='"')
      {
        b.append("\\\"");
      }
      else if (Character.getType(c)==Character.CONTROL)
      {
        b.append('\\');
        b.append(Integer.toOctalString(c));
      }
      else
      {
        b.append(c);
      }
    }
    return b.toString();
  }

  /**
   * Return a string representing the default value of the field if one was provided
   * @param fd
   * @return
   * @throws SourceInterface.SIException
   */
  private static String defaultValueString(FieldDefinition fd)
  throws SourceInterface.SIException
  {
    StringBuilder result=new StringBuilder();
    if (fd.defaultValue!=null)
    {
      switch (fd.type)
      {
      case BLOB :
      case TEXT :
        result.append(" DEFAULT ");
        result.append('\'');
          result.append(escapeJavaString(escapeDBString(fd.defaultValue)));
          result.append('\'');
          break;
      case INTEGER :
        if (fd.javaType.equals("boolean"))
        {
          result.append(" DEFAULT ");
          result.append(fd.defaultValue.equals("true") ? 1 : 0);
          break;
        }
        // Intentionally fall through for non-boolean case
      case REAL :
        try
        {
          double v = Double.parseDouble(fd.defaultValue);
          result.append(" DEFAULT ");
          result.append(v);
        }
        catch (NumberFormatException nfe)
        {
          throw new SourceInterface.SIException(fd.defaultValue + " could not be interpreted as a number");
        }
      default :
        throw new SourceInterface.SIException("Inappropriate field type for getting default value "+fd.type.toString());
      }
    }
    return result.toString();
  }
  
  void generateClassDefinition( PrintWriter pw)
  throws SourceInterface.SIException
  {
    Indenter id=new Indenter(pw);
    pw.println( MessageFormat.format( "// This class was generated from {0}.{1} by a tool", packageName, interfaceName));
    pw.println( "// Do not edit this file directly! PLX THX");
    pw.println( MessageFormat.format( "package {0};", packageName));
    id.nl();
    id.ivprintln( MessageFormat.format( "{2}class {0} extends com.antlersoft.android.dbimpl.{3}ImplementationBase implements {1} '{'",
        implementingClass, interfaceName, makeAbstract ? "abstract " : "", hasId() ? "Id" : ""));
    id.nl();
    id.ivprintln( MessageFormat.format( "static final String {0} = \"{1}\";", TABLE_NAME_SYMBOL, name.toUpperCase()));
    id.ivprintln( MessageFormat.format( "static final int {0} = {1};", FIELD_COUNT_SYMBOL, fieldDefinitions.size()));
    id.nl();
    
    // Write constants for field names and ids
    id.iprintln( "// Field constants");
    for ( int i=0; i<fieldDefinitions.size(); i++)
    {
      FieldDefinition fd=fieldDefinitions.get(i);
      id.ivprintln(MessageFormat.format("static final String {0} = \"{1}\";", nameSymbol(fd), fd.columnName));
      id.ivprintln(MessageFormat.format("static final int {0} = {1};", idSymbol(fd), i));
    }
    id.nl();
    
    // String for creating the table
    id.iprintln("// SQL Command for creating the table");
    id.ivprintln(MessageFormat.format("static String GEN_CREATE = \"CREATE TABLE {0} (\" +", name.toUpperCase()));
    for (int i = 0; i < fieldDefinitions.size(); ++i) {
      FieldDefinition fd = fieldDefinitions.get(i);
      String type = fd.type.toString();
      if (fd.type == FieldType.INTEGER_PRIMARY_KEY) {
        type = "INTEGER PRIMARY KEY AUTOINCREMENT";
      } else {
        if (! fd.nullable)
        {
          type = type + " NOT NULL";
        }
        type = type + defaultValueString(fd);
      }
      id.iprintln(MessageFormat.format("\"{0} {1}{2}\" +", fd.columnName, type, i == fieldDefinitions.size()-1 ? "" : ","));
    }
    id.iprintln("\")\";");
    
    id.nl();
    id.iprintln("// Members corresponding to defined fields");
    // Create variables for fields
    for ( FieldDefinition fd : fieldDefinitions)
    {
      id.indent();
      if ( fd.visibility != FieldVisibility.DEFAULT)
      {
        pw.print( fd.visibility.toString().toLowerCase());
        pw.print(' ');
      }
      pw.print( MessageFormat.format("{0} gen_{1};", fd.javaType, fd.name));
    }
    
    if (! makeAbstract) {
      id.nl();
      id.ivprintln(MessageFormat.format("static final com.antlersoft.android.dbimpl.NewInstance<{0}> GEN_NEW = new com.antlersoft.android.dbimpl.NewInstance<{0}>() '{'", implementingClass));
      id.iprintln(MessageFormat.format("public {0} get() '{'", implementingClass));
      id.iprintln(MessageFormat.format("return new {0}();", implementingClass));
      id.closeBrace();
      id.closeBrace();
      id.iprintln(";");
    }
    
    id.nl();
    id.iprintln(MessageFormat.format("public String Gen_tableName() '{' return {0}; }",TABLE_NAME_SYMBOL));
    
    id.nl();
    // Create accessors for fields
    id.iprintln( "// Field accessors");
    for ( FieldDefinition fd : fieldDefinitions)
    {
      if ( fd.getRequired)
      {
        id.iprintln( MessageFormat.format("public {0} {1}() '{' return gen_{2}; '}'", fd.javaType, fd.getName, fd.name));
      }
      if ( fd.putRequired)
      {
        id.iprintln( MessageFormat.format("public void {0}({1} arg_{2}) '{' gen_{2} = arg_{2}; '}'", fd.putName, fd.javaType, fd.name));
      }
    }
    id.nl();
    id.iprintln( "public android.content.ContentValues Gen_getValues() {");
    id.iprintln( "android.content.ContentValues values=new android.content.ContentValues();");
    for ( FieldDefinition fd : fieldDefinitions)
    {
      String stringValue = "this.gen_" + fd.name; 
      if ( ! fd.javaTypeCode.equals("Ljava/lang/String;"))
      {
        if ( fd.javaTypeCode.startsWith(TypeParse.ARG_OBJREF))
          stringValue = stringValue + ".toString()";
        else if ( fd.javaTypeCode.equals(TypeParse.ARG_BOOLEAN))
        {
          stringValue = MessageFormat.format("({0} ? \"1\" : \"0\")", stringValue);
        }
        else
        {
          stringValue = MessageFormat.format("{0}.toString({1})", getObjectType(fd), stringValue);
        }
      }
      id.iprintln(MessageFormat.format("values.put({0},{1});", nameSymbol(fd), stringValue));
    }
    id.iprintln("return values;");
    id.closeBrace();
    
    id.nl();
    id.iprintln( "/**");
    id.iprintln(" * Return an array that gives the column index in the cursor for each field defined");
    id.iprintln(" * @param cursor Database cursor over some columns, possibly including this table");
    id.iprintln(" * @return array of column indices; -1 if the column with that id is not in cursor");
    id.iprintln(" */");
    id.ivprintln("int[] Gen_columnIndices(android.database.Cursor cursor) {");
    id.iprintln(MessageFormat.format("int[] result=new int[{0}];",FIELD_COUNT_SYMBOL));
    for (int i=0; i<fieldDefinitions.size(); i++)
    {
      FieldDefinition fd=fieldDefinitions.get(i);
      id.iprintln(MessageFormat.format("result[{0}] = cursor.getColumnIndex({1});", i, nameSymbol(fd)));
      if (i == 0 && nameSymbol(fd).equals("GEN_FIELD__ID"))
      {
        id.iprintln("// Make compatible with database generated by older version of plugin with uppercase column name");
        id.iprintln("if (result[0] == -1) {");
        id.iprintln("result[0] = cursor.getColumnIndex(\"_ID\");");
        id.closeBrace();
      }
    }
    id.iprintln("return result;");
    id.closeBrace();
    
    id.nl();
    id.iprintln("/**");
    id.iprintln(" * Populate one instance from a cursor ");
    id.iprintln(" */" );
    id.ivprintln("void Gen_populate(android.database.Cursor cursor,int[] columnIndices) {");
    for (int i = 0; i < fieldDefinitions.size(); i++)
    {
      FieldDefinition fd=fieldDefinitions.get(i);
      id.iprintln(MessageFormat.format("if ( columnIndices[{0}] >= 0 && ! cursor.isNull(columnIndices[{0}])) '{'", idSymbol(fd)));
      switch (fd.type){
      case INTEGER :
      case INTEGER_PRIMARY_KEY :
        if (fd.javaType.equals("boolean")) {
          id.iprintln(MessageFormat.format("gen_{0} = (cursor.getInt(columnIndices[{1}]) != 0);",fd.name,idSymbol(fd)));
        } else if (fd.javaType.equals("long")) {
          id.iprintln(MessageFormat.format("gen_{0} = cursor.getLong(columnIndices[{1}]);",fd.name,idSymbol(fd)));          
        } else {
          id.iprintln(MessageFormat.format("gen_{0} = ({1})cursor.getInt(columnIndices[{2}]);",fd.name,fd.javaType,idSymbol(fd)));
        }
        break;
      case REAL :
        if (fd.javaType.equals("float")) {
          id.iprintln(MessageFormat.format("gen_{0} = cursor.getFloat(columnIndices[{1}]);", fd.name, idSymbol(fd)));
        } else {
          id.iprintln(MessageFormat.format("gen_{0} = cursor.getDouble(columnIndices[{1}]);", fd.name, idSymbol(fd)));
        }
        break;
      case TEXT :
        if (fd.javaType.equals("char")) {
          id.iprintln(MessageFormat.format("gen_{0} = cursor.getString(columnIndices[{1}]).charAt(0);", fd.name, idSymbol(fd)));
        } else {
          id.iprintln(MessageFormat.format("gen_{0} = cursor.getString(columnIndices[{1}]);", fd.name, idSymbol(fd)));
        }
      }
      id.closeBrace();
    }
    id.closeBrace();
    
    id.nl();
    id.iprintln("/**");
    id.iprintln(" * Populate one instance from a ContentValues ");
    id.iprintln(" */" );
    id.ivprintln("void Gen_populate(android.content.ContentValues values) {");
    for (int i = 0; i < fieldDefinitions.size(); i++)
    {
      FieldDefinition fd=fieldDefinitions.get(i);
      switch (fd.type){
      case INTEGER :
      case INTEGER_PRIMARY_KEY :
        if (fd.javaType.equals("boolean")) {
          id.iprintln(MessageFormat.format("gen_{0} = (values.getAsInteger({1}) != 0);",fd.name,nameSymbol(fd)));
        } else if (fd.javaType.equals("long")) {
          id.iprintln(MessageFormat.format("gen_{0} = values.getAsLong({1});",fd.name,nameSymbol(fd)));          
        } else {
          id.iprintln(MessageFormat.format("gen_{0} = ({2})values.getAsInteger({1});",fd.name,nameSymbol(fd),fd.javaType));
        }
        break;
      case REAL :
        if (fd.javaType.equals("float")) {
          id.iprintln(MessageFormat.format("gen_{0} = values.getAsFloat({1});", fd.name, nameSymbol(fd)));
        } else {
          id.iprintln(MessageFormat.format("gen_{0} = values.getAsDouble({1});", fd.name, nameSymbol(fd)));
        }
        break;
      case TEXT :
        if (fd.javaType.equals("char")) {
          id.iprintln(MessageFormat.format("gen_{0} = values.getAsString({1}).charAt(0);", fd.name, nameSymbol(fd)));
        } else {
          id.iprintln(MessageFormat.format("gen_{0} = values.getAsString({1});", fd.name, nameSymbol(fd)));
        }
      }
    }
    id.closeBrace();
    // End of class
    id.closeBrace();
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.