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)
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
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 }