View Javadoc
1   package com.atlassian.activeobjects.backup;
2   
3   import com.atlassian.dbexporter.Column;
4   import com.atlassian.dbexporter.DatabaseInformation;
5   import com.atlassian.dbexporter.DatabaseInformations;
6   import com.atlassian.dbexporter.EntityNameProcessor;
7   import com.atlassian.dbexporter.ImportExportErrorService;
8   import com.atlassian.dbexporter.Table;
9   import com.atlassian.dbexporter.importer.TableCreator;
10  import com.atlassian.dbexporter.progress.ProgressMonitor;
11  import net.java.ao.DatabaseProvider;
12  import net.java.ao.schema.NameConverters;
13  import net.java.ao.schema.ddl.DDLAction;
14  import net.java.ao.schema.ddl.DDLActionType;
15  import net.java.ao.schema.ddl.DDLField;
16  import net.java.ao.schema.ddl.DDLTable;
17  import net.java.ao.schema.ddl.SQLAction;
18  import net.java.ao.types.TypeInfo;
19  import net.java.ao.types.TypeManager;
20  import net.java.ao.types.TypeQualifiers;
21  import org.slf4j.Logger;
22  import org.slf4j.LoggerFactory;
23  
24  import java.sql.Connection;
25  import java.sql.SQLException;
26  import java.sql.Statement;
27  import java.sql.Types;
28  import java.util.List;
29  
30  import static com.atlassian.activeobjects.backup.SqlUtils.executeUpdate;
31  import static com.atlassian.dbexporter.jdbc.JdbcUtils.closeQuietly;
32  import static com.google.common.base.Preconditions.checkNotNull;
33  import static com.google.common.collect.Lists.newArrayList;
34  
35  final class ActiveObjectsTableCreator implements TableCreator {
36      private final Logger logger = LoggerFactory.getLogger("net.java.ao.sql");
37  
38      private final ImportExportErrorService errorService;
39      private final DatabaseProvider provider;
40      private final NameConverters converters;
41  
42      public ActiveObjectsTableCreator(ImportExportErrorService errorService, DatabaseProvider provider, NameConverters converters) {
43          this.errorService = checkNotNull(errorService);
44          this.provider = checkNotNull(provider);
45          this.converters = checkNotNull(converters);
46      }
47  
48      public void create(DatabaseInformation databaseInformation, Iterable<Table> tables, EntityNameProcessor entityNameProcessor, ProgressMonitor monitor) {
49          Connection conn = null;
50          Statement stmt = null;
51          try {
52              conn = provider.getConnection();
53              stmt = conn.createStatement();
54  
55              for (Table table : tables) {
56                  monitor.begin(ProgressMonitor.Task.TABLE_CREATION, entityNameProcessor.tableName(table.getName()));
57                  create(DatabaseInformations.database(databaseInformation), stmt, table, entityNameProcessor);
58                  monitor.end(ProgressMonitor.Task.TABLE_CREATION, entityNameProcessor.tableName(table.getName()));
59              }
60          } catch (SQLException e) {
61              throw errorService.newImportExportSqlException(null, "", e);
62          } finally {
63              closeQuietly(stmt);
64              closeQuietly(conn);
65          }
66      }
67  
68      private void create(DatabaseInformations.Database db, Statement stmt, Table table, EntityNameProcessor entityNameProcessor) {
69          final DDLAction a = new DDLAction(DDLActionType.CREATE);
70          a.setTable(toDdlTable(exportTypeManager(db), entityNameProcessor, table));
71          final Iterable<SQLAction> sqlStatements = provider.renderAction(converters, a);
72          for (SQLAction sql : sqlStatements) {
73              executeUpdate(errorService, table.getName(), stmt, sql.getStatement());
74          }
75      }
76  
77      private DDLTable toDdlTable(TypeManager exportTypeManager, EntityNameProcessor entityNameProcessor, Table table) {
78          final DDLTable ddlTable = new DDLTable();
79          ddlTable.setName(entityNameProcessor.tableName(table.getName()));
80  
81          final List<DDLField> fields = newArrayList();
82          for (Column column : table.getColumns()) {
83              fields.add(toDdlField(exportTypeManager, entityNameProcessor, column));
84          }
85          ddlTable.setFields(fields.toArray(new DDLField[fields.size()]));
86          return ddlTable;
87      }
88  
89      private DDLField toDdlField(TypeManager exportTypeManager, EntityNameProcessor entityNameProcessor, Column column) {
90          final DDLField ddlField = new DDLField();
91          ddlField.setName(entityNameProcessor.columnName(column.getName()));
92  
93          TypeInfo<?> typeFromSchema = getTypeInfo(exportTypeManager, column);
94          ddlField.setType(typeFromSchema);
95          ddlField.setJdbcType(typeFromSchema.getJdbcWriteType());
96  
97          final Boolean pk = column.isPrimaryKey();
98          if (pk != null) {
99              ddlField.setPrimaryKey(pk);
100         }
101         final Boolean autoIncrement = column.isAutoIncrement();
102         if (autoIncrement != null) {
103             ddlField.setAutoIncrement(autoIncrement);
104         }
105         return ddlField;
106     }
107 
108     private TypeInfo<?> getTypeInfo(TypeManager exportTypeManager, Column column) {
109         final TypeQualifiers qualifiers = getQualifiers(column);
110         final TypeInfo<?> exportedType = exportTypeManager.getTypeFromSchema(getSqlType(column), qualifiers);
111         final Class<?> javaType = exportedType.getLogicalType().getTypes().iterator().next();
112 
113         TypeInfo<?> type = provider.getTypeManager().getType(javaType, exportedType.getQualifiers());
114         return type;
115     }
116 
117     private int getSqlType(Column column) {
118         if (column.getSqlType() == Types.NUMERIC) // dealing with Oracle, crappy I know
119         {
120             if (column.getScale() != null && column.getScale() > 0) {
121                 return Types.DOUBLE;
122             } else if (column.getPrecision() != null) {
123                 switch (column.getPrecision()) {
124                     case 1:
125                         return Types.BOOLEAN;
126                     case 11:
127                         return Types.INTEGER;
128                     case 126:
129                         return Types.DOUBLE;
130                     default:
131                         return Types.BIGINT;
132                 }
133             } else {
134                 throw new IllegalStateException("Could not determine the proper mapping from Oracle export, for column:" + column.getName());
135             }
136         }
137         return column.getSqlType();
138     }
139 
140     private TypeQualifiers getQualifiers(Column column) {
141         TypeQualifiers qualifiers = TypeQualifiers.qualifiers();
142         if (isString(column)) {
143             qualifiers = qualifiers.stringLength(column.getPrecision());
144         }
145         return qualifiers;
146     }
147 
148     private boolean isString(Column column) {
149         final int sqlType = getSqlType(column);
150         return
151                 sqlType == Types.CHAR
152                         || sqlType == Types.LONGNVARCHAR
153                         || sqlType == Types.NCHAR
154                         || sqlType == Types.VARCHAR
155                         || sqlType == Types.CLOB
156                         || sqlType == Types.NCLOB
157                         || sqlType == Types.NVARCHAR;
158     }
159 
160     /**
161      * Retrives the type managers of the export from the read database info.
162      */
163     private TypeManager exportTypeManager(DatabaseInformations.Database db) {
164         switch (db.getType()) {
165             case H2:
166                 return TypeManager.h2();
167             case HSQL:
168                 return TypeManager.hsql();
169             case MYSQL:
170                 return TypeManager.mysql();
171             case POSTGRES:
172                 return TypeManager.postgres();
173             case MSSQL:
174                 return TypeManager.sqlServer();
175             case ORACLE:
176                 return TypeManager.oracle();
177             case UNKNOWN:
178             default:
179                 throw errorService.newImportExportException(null, "Could not determine the source database");
180         }
181     }
182 }