1 package com.atlassian.activeobjects.backup;
2
3 import com.atlassian.dbexporter.Column;
4 import com.atlassian.dbexporter.DatabaseInformation;
5 import com.atlassian.dbexporter.EntityNameProcessor;
6 import com.atlassian.dbexporter.ForeignKey;
7 import com.atlassian.dbexporter.ImportExportErrorService;
8 import com.atlassian.dbexporter.Table;
9 import com.atlassian.dbexporter.exporter.TableReader;
10 import com.google.common.base.Function;
11 import com.google.common.collect.Collections2;
12 import com.google.common.collect.Lists;
13 import net.java.ao.DatabaseProvider;
14 import net.java.ao.SchemaConfiguration;
15 import net.java.ao.schema.NameConverters;
16 import net.java.ao.schema.ddl.DDLField;
17 import net.java.ao.schema.ddl.DDLForeignKey;
18 import net.java.ao.schema.ddl.DDLTable;
19 import net.java.ao.schema.ddl.SchemaReader;
20
21 import java.sql.Connection;
22 import java.sql.SQLException;
23 import java.util.Collection;
24 import java.util.List;
25
26 import static com.google.common.base.Preconditions.checkNotNull;
27 import static com.google.common.collect.Lists.newArrayList;
28 import static net.java.ao.sql.SqlUtils.closeQuietly;
29
30 public final class ActiveObjectsTableReader implements TableReader {
31 private final ImportExportErrorService errorService;
32 private final DatabaseProvider provider;
33 private final NameConverters converters;
34 private final SchemaConfiguration schemaConfiguration;
35
36 public ActiveObjectsTableReader(ImportExportErrorService errorService, NameConverters converters, DatabaseProvider provider, SchemaConfiguration schemaConfiguration) {
37 this.converters = checkNotNull(converters);
38 this.errorService = checkNotNull(errorService);
39 this.provider = checkNotNull(provider);
40 this.schemaConfiguration = checkNotNull(schemaConfiguration);
41 }
42
43 @Override
44 public Iterable<Table> read(DatabaseInformation databaseInformation, EntityNameProcessor entityNameProcessor) {
45 final List<Table> tables = newArrayList();
46 final DDLTable[] ddlTables;
47 Connection connection = null;
48 try {
49 connection = getConnection();
50 ddlTables = SchemaReader.readSchema(connection, provider, converters, schemaConfiguration, true);
51 } catch (SQLException e) {
52 throw errorService.newImportExportSqlException(null, "An error occurred reading schema information from database", e);
53 } finally {
54 closeQuietly(connection);
55 }
56 for (DDLTable ddlTable : ddlTables) {
57 tables.add(readTable(ddlTable, entityNameProcessor));
58 }
59 return tables;
60 }
61
62 private Connection getConnection() {
63 try {
64 return provider.getConnection();
65 } catch (SQLException e) {
66 throw errorService.newImportExportSqlException(null, "Could not get connection from provider", e);
67 }
68 }
69
70 private Table readTable(DDLTable ddlTable, EntityNameProcessor processor) {
71 final String name = processor.tableName(ddlTable.getName());
72 return new Table(name, readColumns(ddlTable.getFields(), processor), readForeignKeys(ddlTable.getForeignKeys()));
73 }
74
75 private List<Column> readColumns(DDLField[] fields, final EntityNameProcessor processor) {
76 return Lists.transform(newArrayList(fields), new Function<DDLField, Column>() {
77 @Override
78 public Column apply(DDLField field) {
79 return readColumn(field, processor);
80 }
81 });
82 }
83
84 private Column readColumn(DDLField field, EntityNameProcessor processor) {
85 final String name = processor.columnName(field.getName());
86 return
87 new Column(name, getType(field), field.isPrimaryKey(), field.isAutoIncrement(),
88 getPrecision(field), getScale(field));
89 }
90
91 private int getType(DDLField field) {
92 return field.getJdbcType();
93 }
94
95 private Integer getScale(DDLField field) {
96 return field.getType().getQualifiers().getScale();
97 }
98
99 private Integer getPrecision(DDLField field) {
100 Integer precision = field.getType().getQualifiers().getPrecision();
101 return precision != null ? precision : field.getType().getQualifiers().getStringLength();
102 }
103
104 private Collection<ForeignKey> readForeignKeys(DDLForeignKey[] foreignKeys) {
105 return Collections2.transform(newArrayList(foreignKeys), new Function<DDLForeignKey, ForeignKey>() {
106 public ForeignKey apply(DDLForeignKey fk) {
107 return readForeignKey(fk);
108 }
109 });
110 }
111
112 private ForeignKey readForeignKey(DDLForeignKey fk) {
113 return new ForeignKey(fk.getDomesticTable(), fk.getField(), fk.getTable(), fk.getForeignField());
114 }
115 }