#374 - removed old ddl generation mechanism

This commit is contained in:
Robin Bygrave
2015-08-06 12:04:41 +12:00
parent 7f06863b19
commit c0ef6d8b34
19 changed files with 18 additions and 1831 deletions
@@ -249,7 +249,7 @@ public final class DefaultServer implements SpiEbeanServer {
for (SpiEbeanPlugin plugin : ServiceLoader.load(SpiEbeanPlugin.class)) {
spiPlugins.add(plugin);
plugin.setup(this, this.getDatabasePlatform(), config);
plugin.setup(this, config);
if (plugin instanceof DdlGenerator) {
// backwards compatible
@@ -261,7 +261,7 @@ public final class DefaultServer implements SpiEbeanServer {
// ServiceLoader not finding ddlGenerator (typically OSGi)
ddlGenerator = new DdlGenerator();
spiPlugins.add(ddlGenerator);
ddlGenerator.setup(this, this.getDatabasePlatform(), config);
ddlGenerator.setup(this, config);
}
ebeanPlugins = Collections.unmodifiableList(spiPlugins);
@@ -1,46 +0,0 @@
package com.avaje.ebeaninternal.server.ddl;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
import com.avaje.ebeaninternal.server.deploy.InheritInfoVisitor;
/**
* Base BeanVisitor that can help visiting inherited properties.
*
* @author rbygrave
*/
public abstract class AbstractBeanVisitor implements BeanVisitor {
/**
* Visit all the other inheritance properties that are not on the root.
*/
public void visitInheritanceProperties(BeanDescriptor<?> descriptor, PropertyVisitor pv) {
InheritInfo inheritInfo = descriptor.getInheritInfo();
if (inheritInfo != null && inheritInfo.isRoot()){
// add all properties on the children objects
InheritChildVisitor childVisitor = new InheritChildVisitor(pv);
inheritInfo.visitChildren(childVisitor);
}
}
/**
* Helper used to visit all the inheritInfo/BeanDescriptor in
* the inheritance hierarchy (to add their 'local' properties).
*/
protected static class InheritChildVisitor implements InheritInfoVisitor {
final PropertyVisitor pv;
protected InheritChildVisitor(PropertyVisitor pv) {
this.pv = pv;
}
public void visit(InheritInfo inheritInfo) {
BeanProperty[] propertiesLocal = inheritInfo.getBeanDescriptor().propertiesLocal();
VisitorUtil.visit(propertiesLocal, pv);
}
}
}
@@ -1,41 +0,0 @@
package com.avaje.ebeaninternal.server.ddl;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
/**
* Has no implementation. Can be used as a base object so that
* selective methods can be implemented.
*/
public abstract class AbstractPropertyVisitor implements PropertyVisitor {
public void visitEmbedded(BeanPropertyAssocOne<?> p) {
}
public void visitEmbeddedScalar(BeanProperty p, BeanPropertyAssocOne<?> embedded) {
}
public void visitMany(BeanPropertyAssocMany<?> p) {
}
public void visitOneExported(BeanPropertyAssocOne<?> p) {
}
public void visitOneImported(BeanPropertyAssocOne<?> p) {
}
public void visitScalar(BeanProperty p) {
}
public void visitCompound(BeanPropertyCompound p) {
}
public void visitCompoundScalar(BeanPropertyCompound compound, BeanProperty p) {
}
}
@@ -1,166 +0,0 @@
package com.avaje.ebeaninternal.server.ddl;
import com.avaje.ebean.config.dbplatform.DbDdlSyntax;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
import com.avaje.ebeaninternal.server.deploy.TableJoin;
import com.avaje.ebeaninternal.server.deploy.TableJoinColumn;
/**
* Used to generate the foreign key DDL and related indexes.
*/
public class AddForeignKeysVisitor extends AbstractBeanVisitor {
final DdlGenContext ctx;
final FkeyPropertyVisitor pv;
public AddForeignKeysVisitor(boolean addMode, DdlGenContext ctx) {
this.ctx = ctx;
this.pv = new FkeyPropertyVisitor(addMode, this, ctx);
}
public boolean visitBean(BeanDescriptor<?> descriptor) {
return descriptor.isInheritanceRoot();
}
public void visitBeanEnd(BeanDescriptor<?> descriptor) {
visitInheritanceProperties(descriptor, pv);
}
public void visitBegin() {
}
public void visitEnd() {
ctx.addIntersectionFkeys();
}
public PropertyVisitor visitProperty(BeanProperty p) {
return pv;
}
public static class FkeyPropertyVisitor extends BaseTablePropertyVisitor {
/**
* Set to false when generating drop foreign key statements.
*/
final boolean addMode;
final DdlGenContext ctx;
final AddForeignKeysVisitor parent;
public FkeyPropertyVisitor(boolean addMode, AddForeignKeysVisitor parent, DdlGenContext ctx) {
this.addMode = addMode;
this.parent = parent;
this.ctx = ctx;
}
@Override
public void visitEmbeddedScalar(BeanProperty p, BeanPropertyAssocOne<?> embedded) {
// not interested
}
@Override
public void visitOneImported(BeanPropertyAssocOne<?> p) {
// alter table {basetable} add foreign key (...) references {} (...) on delete restrict on update restrict;
// Alter table o_address add Foreign Key (country_code) references o_country (code) on delete restrict on update restrict;
String baseTable = p.getBeanDescriptor().getBaseTable();
TableJoin tableJoin = p.getTableJoin();
TableJoinColumn[] columns = tableJoin.columns();
String tableName = p.getBeanDescriptor().getBaseTable();
DbDdlSyntax ddlSyntax = ctx.getDdlSyntax();
String fkName = ddlSyntax.getForeignKeyName(tableName, p.getName(), ctx.incrementFkCount());
if (!addMode) {
// look to generate drop foreign key statement
String dropKeyConstraintPrefix = ddlSyntax.dropKeyConstraintPrefix(tableName, fkName);
if (dropKeyConstraintPrefix != null && !dropKeyConstraintPrefix.isEmpty()) {
ctx.write(dropKeyConstraintPrefix).write(" ");
}
}
ctx.write("alter table ").write(baseTable).write(addOrDrop());
if (fkName != null) {
ctx.write("constraint ").write(fkName).write(" ");
}
if (addMode) {
ctx.write("foreign key (");
for (int i = 0; i < columns.length; i++) {
if (i > 0) {
ctx.write(",");
}
ctx.write(columns[i].getLocalDbColumn());
}
ctx.write(")");
ctx.write(" references ");
ctx.write(tableJoin.getTable());
ctx.write(" (");
for (int i = 0; i < columns.length; i++) {
if (i > 0) {
ctx.write(",");
}
ctx.write(columns[i].getForeignDbColumn());
}
ctx.write(")");
String fkeySuffix = ctx.getDdlSyntax().getForeignKeySuffix();
if (fkeySuffix != null) {
ctx.write(" ").write(fkeySuffix);
}
}
ctx.write(";").writeNewLine();
if (addMode && ddlSyntax.isRenderIndexForFkey()){
//create index idx_fk_o_address_ctry on o_address(country_code);
ctx.write("create index ");
String idxName = ddlSyntax.getIndexName(tableName, p.getName(), ctx.incrementIxCount());
if (idxName != null){
ctx.write(idxName);
}
ctx.write(" on ").write(baseTable).write(" (");
for (int i = 0; i < columns.length; i++) {
if (i > 0){
ctx.write(",");
}
ctx.write(columns[i].getLocalDbColumn());
}
ctx.write(");").writeNewLine();
}
}
/**
* Return 'add' or 'drop' of foreign key.
*/
protected String addOrDrop() {
return addMode ? " add " : " drop " ;
}
@Override
public void visitScalar(BeanProperty p) {
// not interested
}
@Override
public void visitCompound(BeanPropertyCompound p) {
// not interested
}
@Override
public void visitCompoundScalar(BeanPropertyCompound compound, BeanProperty p) {
// not interested
}
}
}
@@ -1,60 +0,0 @@
package com.avaje.ebeaninternal.server.ddl;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
/**
* Used to help mark PropertyVisitor methods that need to be implemented
* to visit base table properties.
*/
public abstract class BaseTablePropertyVisitor implements PropertyVisitor {
/**
* Not required in that you can use the visitEmbeddedScalar.
*/
public void visitEmbedded(BeanPropertyAssocOne<?> p) {
}
/**
* Override this method.
*/
public abstract void visitEmbeddedScalar(BeanProperty p, BeanPropertyAssocOne<?> embedded);
/**
* Not part of base table.
*/
public void visitMany(BeanPropertyAssocMany<?> p) {
}
/**
* Not part of base table.
*/
public void visitOneExported(BeanPropertyAssocOne<?> p) {
}
/**
* Override this method for the foreign key.
*/
public abstract void visitOneImported(BeanPropertyAssocOne<?> p);
/**
* Override this method for normal scalar property.
*/
public abstract void visitScalar(BeanProperty p);
/**
* Not required in that the scalar properties map to the columns.
*/
public void visitCompound(BeanPropertyCompound p){
}
/**
* Override this method for scalar property inside a Immutable Compound Value object.
*/
public abstract void visitCompoundScalar(BeanPropertyCompound compound, BeanProperty p);
}
@@ -1,42 +0,0 @@
package com.avaje.ebeaninternal.server.ddl;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
/**
* Visitor pattern for visiting a BeanDescriptor and potentially all its bean
* properties.
*/
public interface BeanVisitor {
/**
* Starting.
*/
void visitBegin();
/**
* Visit a BeanDescriptor and return true to continue visiting the bean
* (return false to skip visiting this bean).
*/
boolean visitBean(BeanDescriptor<?> descriptor);
/**
* Visit a property potentially return a specific PropertyVisitor.
* <p>
* A PropertyVisitor can be returned to more easily process bean properties
* by their specific type.
* </p>
*/
PropertyVisitor visitProperty(BeanProperty p);
/**
* Finished visiting the BeanDescriptor.
*/
void visitBeanEnd(BeanDescriptor<?> descriptor);
/**
* Finished all visiting.
*/
void visitEnd();
}
@@ -1,87 +0,0 @@
package com.avaje.ebeaninternal.server.ddl;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
/**
* A visitor that creates indexes for columns annotated with ColumnIndex
*
* @author rvbiljouw
* @see com.avaje.ebean.annotation.Index
*/
public class CreateIndexVisitor extends AbstractBeanVisitor {
private final IndexPropertyVisitor iv;
public CreateIndexVisitor(DdlGenContext ctx) {
this.iv = new IndexPropertyVisitor(ctx);
}
@Override
public void visitBegin() {
}
@Override
public boolean visitBean(BeanDescriptor<?> descriptor) {
return descriptor.isInheritanceRoot();
}
@Override
public PropertyVisitor visitProperty(BeanProperty p) {
return iv;
}
@Override
public void visitBeanEnd(BeanDescriptor<?> descriptor) {
visitInheritanceProperties(descriptor, iv);
}
@Override
public void visitEnd() {
}
private static final class IndexPropertyVisitor extends BaseTablePropertyVisitor {
private final DdlGenContext ctx;
public IndexPropertyVisitor(DdlGenContext ctx) {
this.ctx = ctx;
}
@Override
public void visitEmbeddedScalar(BeanProperty p, BeanPropertyAssocOne<?> embedded) {
}
@Override
public void visitOneImported(BeanPropertyAssocOne<?> p) {
}
@Override
public void visitScalar(BeanProperty p) {
String baseTable = p.getBeanDescriptor().getBaseTable();
if (p.isIndexed()) {
String indexName = p.getIndexName();
if (indexName.length() == 0) {
indexName = ctx.getDdlSyntax().getIndexName(baseTable, p.getDbColumn(), ctx.incrementIxCount());
}
ctx.write("create index ")
.write(indexName)
.write(" on ")
.write(baseTable)
.write("(")
.write(p.getDbColumn())
.write(");")
.writeNewLine();
}
}
@Override
public void visitCompoundScalar(BeanPropertyCompound compound, BeanProperty p) {
}
}
}
@@ -1,173 +0,0 @@
package com.avaje.ebeaninternal.server.ddl;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.TableJoin;
import com.avaje.ebeaninternal.server.deploy.TableJoinColumn;
/**
* Create the sql to create the intersection table and its foreign key
* constraints.
*/
public class CreateIntersectionTable {
private static final String NEW_LINE = "\n";
private final DdlGenContext ctx;
private final BeanPropertyAssocMany<?> manyProp;
private final TableJoin intersectionTableJoin;
private final TableJoin tableJoin;
private final StringBuilder sb = new StringBuilder();
private final StringBuilder pkeySb = new StringBuilder();
private int foreignKeyCount;
private final int maxFkeyLength;
public CreateIntersectionTable(DdlGenContext ctx, BeanPropertyAssocMany<?> manyProp) {
this.ctx = ctx;
this.manyProp = manyProp;
this.intersectionTableJoin = manyProp.getIntersectionTableJoin();
this.tableJoin = manyProp.getTableJoin();
this.maxFkeyLength = ctx.getDdlSyntax().getMaxConstraintNameLength()-3;
}
public void build() {
String createTable = buildCreateTable();
ctx.addCreateIntersectionTable(createTable);
foreignKeyCount = 0;
buildFkConstraints();
}
private void buildFkConstraints() {
BeanDescriptor<?> localDesc = manyProp.getBeanDescriptor();
String fk1 = buildFkConstraints(localDesc, intersectionTableJoin.columns(), true);
ctx.addIntersectionTableFk(fk1);
BeanDescriptor<?> targetDesc = manyProp.getTargetDescriptor();
String fk2 = buildFkConstraints(targetDesc, tableJoin.columns(), false);
ctx.addIntersectionTableFk(fk2);
}
private String getFkNameSuffix() {
foreignKeyCount++;
if (foreignKeyCount > 9){
return "_"+foreignKeyCount;
} else {
return "_0"+foreignKeyCount;
}
}
private String getFkNameWithSuffix(String fkName) {
if (fkName.length() > maxFkeyLength){
fkName = fkName.substring(0, maxFkeyLength);
}
return fkName+getFkNameSuffix();
}
private String buildFkConstraints(BeanDescriptor<?> desc, TableJoinColumn[] columns, boolean direction) {
StringBuilder fkBuf = new StringBuilder();
String fkName = "fk_"+intersectionTableJoin.getTable()+"_"+desc.getBaseTable();
fkName = getFkNameWithSuffix(fkName);
fkBuf.append("alter table ");
fkBuf.append(intersectionTableJoin.getTable());
fkBuf.append(" add constraint ").append(fkName);
fkBuf.append(" foreign key (");
for (int i = 0; i < columns.length; i++) {
if (i > 0) {
fkBuf.append(", ");
}
String col = direction ? columns[i].getForeignDbColumn() : columns[i].getLocalDbColumn();
fkBuf.append(col);
}
fkBuf.append(") references ").append(desc.getBaseTable()).append(" (");
for (int i = 0; i < columns.length; i++) {
if (i > 0) {
fkBuf.append(", ");
}
String col = !direction ? columns[i].getForeignDbColumn() : columns[i].getLocalDbColumn();
fkBuf.append(col);
}
fkBuf.append(")");
String fkeySuffix = ctx.getDdlSyntax().getForeignKeySuffix();
if (fkeySuffix != null){
fkBuf.append(" ");
fkBuf.append(fkeySuffix);
}
fkBuf.append(";").append(NEW_LINE);
return fkBuf.toString();
}
private String buildCreateTable() {
BeanDescriptor<?> localDesc = manyProp.getBeanDescriptor();
BeanDescriptor<?> targetDesc = manyProp.getTargetDescriptor();
sb.append("create table ");
sb.append(intersectionTableJoin.getTable());
sb.append(" (").append(NEW_LINE);
TableJoinColumn[] columns = intersectionTableJoin.columns();
for (int i = 0; i < columns.length; i++) {
addColumn(localDesc, columns[i].getForeignDbColumn(), columns[i].getLocalDbColumn());
}
TableJoinColumn[] otherColumns = tableJoin.columns();
for (int i = 0; i < otherColumns.length; i++) {
addColumn(targetDesc, otherColumns[i].getLocalDbColumn(), otherColumns[i].getForeignDbColumn());
}
sb.append(" constraint pk_").append(intersectionTableJoin.getTable());
sb.append(" primary key (").append(pkeySb.toString().substring(2));
sb.append("))").append(NEW_LINE).append(";").append(NEW_LINE);
return sb.toString();
}
private void addColumn(BeanDescriptor<?> desc, String column, String findPropColumn) {
pkeySb.append(", ");
pkeySb.append(column);
writeColumn(column);
BeanProperty p = desc.getIdBinder().findBeanProperty(findPropColumn);
if (p == null) {
throw new RuntimeException("Could not find id property for " + findPropColumn);
}
String columnDefn = ctx.getColumnDefn(p);
sb.append(columnDefn);
sb.append(" not null");
sb.append(",").append(NEW_LINE);
}
private void writeColumn(String columnName) {
sb.append(" ").append(ctx.pad(columnName, 30)).append(" ");
}
}
@@ -1,66 +0,0 @@
package com.avaje.ebeaninternal.server.ddl;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Used to generate the drop table DDL script.
*/
public class CreateSequenceVisitor implements BeanVisitor {
private static final Logger logger = LoggerFactory.getLogger(CreateSequenceVisitor.class);
private final DdlGenContext ctx;
private final boolean supportsSequence;
public CreateSequenceVisitor(DdlGenContext ctx) {
this.ctx = ctx;
this.supportsSequence = ctx.getDbPlatform().getDbIdentity().isSupportsSequence();
}
public boolean visitBean(BeanDescriptor<?> descriptor) {
if (!descriptor.isInheritanceRoot()){
return false;
}
if (descriptor.getSequenceName() == null) {
return false;
}
if (!supportsSequence){
// Hopefully a generic test case
String msg = "Not creating sequence "+descriptor.getSequenceName()+" on Bean "+descriptor.getName()
+" as DatabasePlatform does not support sequences";
logger.warn(msg);
return false;
}
String sequenceName = descriptor.getSequenceName();
if (sequenceName != null) {
int initialValue = descriptor.getSequenceInitialValue();
int allocationSize = descriptor.getSequenceAllocationSize();
String createSeq = ctx.getDbPlatform().ddlCreateSequence(sequenceName, initialValue, allocationSize);
ctx.write(createSeq).writeNewLine().writeNewLine();
}
return true;
}
public void visitBeanEnd(BeanDescriptor<?> descriptor) {
}
public void visitBegin() {
}
public void visitEnd() {
}
public PropertyVisitor visitProperty(BeanProperty p) {
// Return null as we are not interested in properties
return null;
}
}
@@ -1,231 +0,0 @@
package com.avaje.ebeaninternal.server.ddl;
import java.sql.Types;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.avaje.ebean.config.TableName;
import com.avaje.ebean.config.dbplatform.DbDdlSyntax;
import com.avaje.ebean.config.dbplatform.IdType;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
import com.avaje.ebeaninternal.server.deploy.TableJoin;
import com.avaje.ebeaninternal.server.deploy.TableJoinColumn;
import com.avaje.ebeaninternal.server.deploy.id.ImportedId;
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
/**
* Used as part of CreateTableVisitor to generated the create table DDL script.
*/
public class CreateTableColumnVisitor extends BaseTablePropertyVisitor {
private static final Logger logger = LoggerFactory.getLogger(CreateTableColumnVisitor.class);
private final DdlGenContext ctx;
private final DbDdlSyntax ddl;
private final CreateTableVisitor parent;
private BeanPropertyAssocOne<?> embedded;
public CreateTableColumnVisitor(CreateTableVisitor parent, DdlGenContext ctx) {
this.parent = parent;
this.ctx = ctx;
this.ddl = ctx.getDdlSyntax();
}
@Override
public void visitMany(BeanPropertyAssocMany<?> p) {
if (p.isManyToMany()) {
//noinspection StatementWithEmptyBody
if (p.getMappedBy() != null) {
// only create on other 'owning' side
} else {
TableJoin intersectionTableJoin = p.getIntersectionTableJoin();
// check if the intersection table has already been created
String intTable = intersectionTableJoin.getTable();
if (ctx.isProcessIntersectionTable(intTable)) {
// build the create table and fkey constraints
// putting the DDL into ctx for later output as we are
// in the middle of rendering the create table DDL
new CreateIntersectionTable(ctx, p).build();
}
}
}
}
public void visitCompoundScalar(BeanPropertyCompound compound, BeanProperty p) {
visitScalar(p);
}
public void visitCompound(BeanPropertyCompound p) {
// do nothing
}
@Override
public void visitEmbeddedScalar(BeanProperty p, BeanPropertyAssocOne<?> embedded) {
this.embedded = embedded;
visitScalar(p);
}
private StringBuilder createUniqueConstraintBuffer(String table, String column) {
String uqConstraintName = "uq_"+TableName.parse(table)+"_"+column;
if (uqConstraintName.length() > ddl.getMaxConstraintNameLength()) {
uqConstraintName = uqConstraintName.substring(0, ddl.getMaxConstraintNameLength());
}
uqConstraintName = ctx.removeQuotes(uqConstraintName);
uqConstraintName = StringHelper.replaceString(uqConstraintName, " ", "_");
StringBuilder constraintExpr = new StringBuilder();
constraintExpr.append("constraint ").append(uqConstraintName).append(" unique (");
return constraintExpr;
}
@Override
public void visitOneImported(BeanPropertyAssocOne<?> p) {
ImportedId importedId = p.getImportedId();
TableJoinColumn[] columns = p.getTableJoin().columns();
if (columns.length == 0) {
String msg = "No join columns for " + p.getFullBeanName();
throw new RuntimeException(msg);
}
StringBuilder constraintExpr = createUniqueConstraintBuffer(p.getBeanDescriptor().getBaseTable(), columns[0].getLocalDbColumn());
for (int i = 0; i < columns.length; i++) {
String dbCol = columns[i].getLocalDbColumn();
if (i > 0) {
constraintExpr.append(", ");
}
constraintExpr.append(dbCol);
if (parent.isDbColumnWritten(dbCol)) {
continue;
}
parent.writeColumnName(dbCol, p);
BeanProperty importedProperty = importedId.findMatchImport(dbCol);
if (importedProperty != null) {
String columnDefn = ctx.getColumnDefn(importedProperty);
ctx.write(columnDefn);
} else {
throw new RuntimeException("Imported BeanProperty not found?");
}
if (!p.isNullable()) {
ctx.write(" not null");
}
ctx.write(",").writeNewLine();
}
constraintExpr.append(")");
if (p.isOneToOne()) {
if (ddl.isAddOneToOneUniqueContraint()) {
parent.addUniqueConstraint(constraintExpr.toString());
}
}
}
@Override
public void visitScalar(BeanProperty p) {
if (p.isSecondaryTable()) {
return;
}
if (parent.isDbColumnWritten(p.getDbColumn())) {
return;
}
parent.writeColumnName(p.getDbColumn(), p);
String columnDefn = ctx.getColumnDefn(p);
boolean identity = isIdentity(p);
if (identity) {
ctx.write(ddl.getIdentityColumnDefn(columnDefn));
} else {
ctx.write(columnDefn);
}
if (p.isId() && ddl.isInlinePrimaryKeyConstraint()){
ctx.write(" primary key");
} else if (!p.isNullable() || p.isDDLNotNull()) {
ctx.write(" not null");
}
if (identity) {
writeIdentitySuffix();
}
if (p.isUnique() && !p.isId()) {
parent.addUniqueConstraint(createUniqueConstraint(p));
}
parent.addCheckConstraint(p);
ctx.write(",").writeNewLine();
}
private String createUniqueConstraint(BeanProperty p) {
String baseTable = p.getBeanDescriptor().getBaseTable();
if (baseTable == null) {
// Embedded bean property that has unique constraint on it
baseTable = embedded.getBeanDescriptor().getBaseTable();
}
StringBuilder expr = createUniqueConstraintBuffer(baseTable, p.getDbColumn());
expr.append(p.getDbColumn()).append(")");
return expr.toString();
}
protected void writeIdentitySuffix() {
String identity = ddl.getIdentitySuffix();
if (identity != null && identity.length() > 0) {
ctx.write(" ").write(identity);
}
}
protected boolean isIdentity(BeanProperty p) {
if (p.isId()) {
try {
IdType idType = p.getBeanDescriptor().getIdType();
if (idType.equals(IdType.IDENTITY)) {
int jdbcType = p.getScalarType().getJdbcType();
if (jdbcType == Types.INTEGER || jdbcType == Types.BIGINT || jdbcType == Types.SMALLINT) {
return true;
}
}
} catch (Exception e) {
String msg = "Error determining identity on property " + p.getFullBeanName();
logger.error(msg, e);
}
}
return false;
}
}
@@ -1,264 +0,0 @@
package com.avaje.ebeaninternal.server.ddl;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.avaje.ebean.config.TableName;
import com.avaje.ebean.config.dbplatform.DbDdlSyntax;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
import com.avaje.ebeaninternal.server.deploy.CompoundUniqueContraint;
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
import com.avaje.ebeaninternal.server.deploy.parse.SqlReservedWords;
/**
* Used to generated the create table DDL script.
*/
public class CreateTableVisitor extends AbstractBeanVisitor {
private static final Logger logger = LoggerFactory.getLogger(CreateTableVisitor.class);
private final DdlGenContext ctx;
private final PropertyVisitor pv;
private final DbDdlSyntax ddl;
private final int columnNameWidth;
// avoid writing columns twice, e.g. when used in associations with insertable=false and updateable=false
private final Set<String> wroteColumns = new HashSet<String>();
private ArrayList<String> checkConstraints = new ArrayList<String>();
private ArrayList<String> uniqueConstraints = new ArrayList<String>();
private String table;
public Set<String> getWroteColumns() {
return wroteColumns;
}
public CreateTableVisitor(DdlGenContext ctx) {
this.ctx = ctx;
this.ddl = ctx.getDdlSyntax();
this.columnNameWidth = ddl.getColumnNameWidth();
this.pv = new CreateTableColumnVisitor(this, ctx);
}
public boolean isDbColumnWritten(String dbColumn) {
// Columns are not case sensitive - user lower case
// as e.g. @JoinColumn(s) may use a different case
return wroteColumns.contains(dbColumn.toLowerCase());
}
public void addDbColumnWritten(String dbColumn) {
// Column names are case insensitive
wroteColumns.add(dbColumn.toLowerCase());
}
/**
* Write the table name including a check for SQL reserved words.
*/
protected void writeTableName(BeanDescriptor<?> descriptor) {
// parse to remove any catalog or schema prefix on the table
table = TableName.parse(descriptor.getBaseTable());
ctx.write(descriptor.getBaseTable());
}
/**
* Write the column name including a check for the SQL reserved words.
*/
protected void writeColumnName(String columnName, BeanProperty p) {
addDbColumnWritten(columnName);
if (SqlReservedWords.isKeyword(columnName)) {
String propName = p == null ? "(Unknown)" : p.getFullBeanName();
logger.warn("Column name [" + columnName + "] is a suspected SQL reserved word for property " + propName);
}
ctx.write(" ").write(columnName, columnNameWidth).write(" ");
}
/**
* Build a check constraint for the property if required.
* <p>
* Typically check constraint based on Enum mapping values.
* </p>
*/
protected void addCheckConstraint(BeanProperty p, String prefix, String constraintExpression) {
if (p != null && constraintExpression != null) {
// build constraint clause
String s = "constraint " + getConstraintName(prefix, p) + " " + constraintExpression;
// add to list as we render all check constraints just prior to primary key
checkConstraints.add(s);
}
}
protected String getConstraintName(String prefix, BeanProperty p) {
return prefix + table + "_" + p.getDbColumn();
}
protected void addUniqueConstraint(String constraintExpression) {
uniqueConstraints.add(constraintExpression);
}
protected void addCheckConstraint(String constraintExpression) {
checkConstraints.add(constraintExpression);
}
protected void addCheckConstraint(BeanProperty p) {
addCheckConstraint(p, "ck_", p.getDbConstraintExpression());
}
public boolean visitBean(BeanDescriptor<?> descriptor) {
wroteColumns.clear();
if (!descriptor.isInheritanceRoot()) {
return false;
}
ctx.write("create table ");
writeTableName(descriptor);
ctx.write(" (").writeNewLine();
InheritInfo inheritInfo = descriptor.getInheritInfo();
if (inheritInfo != null && inheritInfo.isRoot()) {
String discColumn = inheritInfo.getDiscriminatorColumn();
int discType = inheritInfo.getDiscriminatorType();
int discLength = inheritInfo.getDiscriminatorLength();
DbType dbType = ctx.getDbTypeMap().get(discType);
String discDbType = dbType.renderType(discLength, 0);
writeColumnName(discColumn, null);
ctx.write(discDbType);
ctx.write(" not null,");
ctx.writeNewLine();
}
return true;
}
public void visitBeanEnd(BeanDescriptor<?> descriptor) {
visitInheritanceProperties(descriptor, pv);
if (checkConstraints.size() > 0) {
for (String checkConstraint : checkConstraints) {
ctx.write(" ").write(checkConstraint).write(",").writeNewLine();
}
checkConstraints = new ArrayList<String>();
}
if (uniqueConstraints.size() > 0) {
for (String constraint : uniqueConstraints) {
ctx.write(" ").write(constraint).write(",").writeNewLine();
}
uniqueConstraints = new ArrayList<String>();
}
CompoundUniqueContraint[] compoundUniqueConstraints = descriptor.getCompoundUniqueConstraints();
if (compoundUniqueConstraints != null) {
String table = descriptor.getBaseTable();
for (int i = 0; i < compoundUniqueConstraints.length; i++) {
String constraint = createUniqueConstraint(table, i, compoundUniqueConstraints[i]);
ctx.write(" ").write(constraint).write(",").writeNewLine();
}
}
BeanProperty idProp = descriptor.getIdProperty();
if (idProp == null) {
// No comma + new line
ctx.removeLast().removeLast();
} else if (ddl.isInlinePrimaryKeyConstraint()) {
// The Primary Key constraint was inlined with the column
// ... No comma + new line
ctx.removeLast().removeLast();
} else {
// Add the primay key constraint
String pkName = ddl.getPrimaryKeyName(table);
ctx.write(" constraint ").write(pkName).write(" primary key (");
VisitorUtil.visit(idProp, new AbstractPropertyVisitor() {
@Override
public void visitEmbeddedScalar(BeanProperty p, BeanPropertyAssocOne<?> embedded) {
ctx.write(p.getDbColumn()).write(", ");
}
@Override
public void visitScalar(BeanProperty p) {
ctx.write(p.getDbColumn()).write(", ");
}
@Override
public void visitCompoundScalar(BeanPropertyCompound compound, BeanProperty p) {
ctx.write(p.getDbColumn()).write(", ");
}
});
// remove the last comma, end of PK
ctx.removeLast().write(")");
}
// end of table
ctx.write(")").writeNewLine();
ctx.write(";").writeNewLine().writeNewLine();
ctx.flush();
}
private String createUniqueConstraint(String table, int idx, CompoundUniqueContraint uc) {
StringBuilder sb = new StringBuilder(50);
sb.append("constraint ")
.append("uq_").append(TableName.parse(table)).append("_").append(idx + 1)
.append(" unique (");
String[] columns = uc.getColumns();
for (int i = 0; i < columns.length; i++) {
if (i > 0) {
sb.append(",");
}
sb.append(columns[i]);
}
sb.append(")");
return sb.toString();
}
public void visitBeanDescriptorEnd() {
ctx.write(");").writeNewLine().writeNewLine();
}
public PropertyVisitor visitProperty(BeanProperty p) {
return pv;
}
public void visitBegin() {
}
public void visitEnd() {
ctx.addIntersectionCreateTables();
ctx.flush();
}
}
@@ -1,252 +0,0 @@
package com.avaje.ebeaninternal.server.ddl;
import java.io.StringWriter;
import java.sql.Types;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.avaje.ebean.config.NamingConvention;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.DbDdlSyntax;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebean.config.dbplatform.DbTypeMap;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
import com.avaje.ebeaninternal.server.type.ScalarType;
/**
* The context used during DDL generation.
*/
public class DdlGenContext {
private final StringWriter stringWriter = new StringWriter();
/**
* Used to map bean types to DB specific types.
*/
private final DbTypeMap dbTypeMap;
/**
* Handles DB specific DDL syntax.
*/
private final DbDdlSyntax ddlSyntax;
/**
* The new line character that is used.
*/
private final String newLine;
/**
* Last content written (used with removeLast())
*/
private final List<String> contentBuffer = new ArrayList<String>();
private final Set<String> intersectionTables = new HashSet<String>();
private final List<String> intersectionTablesCreateDdl = new ArrayList<String>();
private final List<String> intersectionTablesFkDdl = new ArrayList<String>();
private final DatabasePlatform dbPlatform;
/** The Naming convention used to define FK an IX names */
private final NamingConvention namingConvention;
/** The global fk count used to keep FK names unique */
private int fkCount;
/** The ix count. */
private int ixCount;
public DdlGenContext(DatabasePlatform dbPlatform, NamingConvention namingConvention){
this.dbPlatform = dbPlatform;
this.dbTypeMap = dbPlatform.getDbTypeMap();
this.ddlSyntax = dbPlatform.getDbDdlSyntax();
this.newLine = ddlSyntax.getNewLine();
this.namingConvention = namingConvention;
}
/**
* Return the dbPlatform.
*/
public DatabasePlatform getDbPlatform() {
return dbPlatform;
}
public boolean isProcessIntersectionTable(String tableName){
return intersectionTables.add(tableName);
}
public void addCreateIntersectionTable(String createTableDdl){
intersectionTablesCreateDdl.add(createTableDdl);
}
public void addIntersectionTableFk(String intTableFk){
intersectionTablesFkDdl.add(intTableFk);
}
public void addIntersectionCreateTables() {
for (String intTableCreate : intersectionTablesCreateDdl) {
write(newLine);
write(intTableCreate);
}
}
public void addIntersectionFkeys() {
write(newLine);
write(newLine);
for (String intTableFk : intersectionTablesFkDdl) {
write(newLine);
write(intTableFk);
}
}
/**
* Return the generated content (DDL script).
*/
public String getContent(){
return stringWriter.toString();
}
/**
* Return the map used to determine the DB specific type
* for a given bean property.
*/
public DbTypeMap getDbTypeMap() {
return dbTypeMap;
}
/**
* Return object to handle DB specific DDL syntax.
*/
public DbDdlSyntax getDdlSyntax() {
return ddlSyntax;
}
public String getColumnDefn(BeanProperty p) {
DbType dbType = getDbType(p);
return p.renderDbType(dbType);
}
private DbType getDbType(BeanProperty p) {
ScalarType<?> scalarType = p.getScalarType();
if (scalarType == null) {
throw new RuntimeException("No scalarType for " + p.getFullBeanName());
}
if (p.isDbEncrypted()){
return dbTypeMap.get(p.getDbEncryptedType());
}
int jdbcType = scalarType.getJdbcType();
if (p.isLob() && jdbcType == Types.VARCHAR){
// workaround for Postgres TEXT type which is
// VARCHAR in jdbc API but TEXT in ddl
jdbcType = Types.CLOB;
}
return dbTypeMap.get(jdbcType);
}
/**
* Write content to the buffer.
*/
public DdlGenContext write(String content, int minWidth){
content = pad(content, minWidth);
contentBuffer.add(content);
return this;
}
/**
* Write content to the buffer.
*/
public DdlGenContext write(String content){
return write(content, 0);
}
public DdlGenContext writeNewLine() {
write(newLine);
return this;
}
/**
* Remove the last content that was written.
*/
public DdlGenContext removeLast() {
if (!contentBuffer.isEmpty()){
contentBuffer.remove(contentBuffer.size()-1);
} else {
throw new RuntimeException("No lastContent to remove?");
}
return this;
}
/**
* Flush the content to the buffer.
*/
public DdlGenContext flush() {
if (!contentBuffer.isEmpty()){
for (String s:contentBuffer){
if (s != null){
stringWriter.write(s);
}
}
contentBuffer.clear();
}
return this;
}
private String padding(int length){
StringBuilder sb = new StringBuilder(length);
for (int i = 0; i < length; i++) {
sb.append(" ");
}
return sb.toString();
}
public String pad(String content, int minWidth){
if (minWidth > 0 && content.length() < minWidth){
int padding = minWidth - content.length();
return content + padding(padding);
}
return content;
}
/**
* @return the namingConvention
*/
public NamingConvention getNamingConvention() {
return namingConvention;
}
/**
* @return the incremented fkCount
*/
public int incrementFkCount() {
return ++fkCount;
}
/**
* @return the incremented ixCount
*/
public int incrementIxCount() {
return ++ixCount;
}
/**
* Strips off the Database Platform specific quoted identifier characters.
*/
public String removeQuotes(String dbColumn) {
dbColumn = StringHelper.replaceString(dbColumn, dbPlatform.getOpenQuote(), "");
dbColumn = StringHelper.replaceString(dbColumn, dbPlatform.getCloseQuote(), "");
return dbColumn;
}
}
@@ -1,5 +1,14 @@
package com.avaje.ebeaninternal.server.ddl;
import com.avaje.ebean.Transaction;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.dbmigration.model.CurrentModel;
import com.avaje.ebeaninternal.api.SpiEbeanPlugin;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.PersistenceException;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
@@ -13,19 +22,6 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.PersistenceException;
import com.avaje.ebean.dbmigration.model.CurrentModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.avaje.ebean.Transaction;
import com.avaje.ebean.config.NamingConvention;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebeaninternal.api.SpiEbeanPlugin;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
/**
* Controls the generation of DDL and potentially runs the resulting scripts.
*/
@@ -35,8 +31,6 @@ public class DdlGenerator implements SpiEbeanPlugin {
private SpiEbeanServer server;
private DatabasePlatform dbPlatform;
private boolean generateDdl;
private boolean runDdl;
@@ -44,14 +38,10 @@ public class DdlGenerator implements SpiEbeanPlugin {
private String dropContent;
private String createContent;
private NamingConvention namingConvention;
public void setup(SpiEbeanServer server, DatabasePlatform dbPlatform, ServerConfig serverConfig) {
public void setup(SpiEbeanServer server, ServerConfig serverConfig) {
this.server = server;
this.dbPlatform = dbPlatform;
this.generateDdl = serverConfig.isDdlGenerate();
this.runDdl = serverConfig.isDdlRun();
this.namingConvention = serverConfig.getNamingConvention();
}
/**
@@ -134,25 +124,8 @@ public class DdlGenerator implements SpiEbeanPlugin {
} catch (IOException e) {
throw new RuntimeException(e);
}
// DdlGenContext ctx = createContext();
//
// if (ctx.getDdlSyntax().isDropKeyConstraints()) {
// // generate drop foreign key constraint statements (sql server joy)
// AddForeignKeysVisitor fkeys = new AddForeignKeysVisitor(false, ctx);
// VisitorUtil.visit(server, fkeys);
// ctx.writeNewLine();
// }
//
// DropTableVisitor drop = new DropTableVisitor(ctx);
// VisitorUtil.visit(server, drop);
//
// DropSequenceVisitor dropSequence = new DropSequenceVisitor(ctx);
// VisitorUtil.visit(server, dropSequence);
//
// ctx.flush();
// dropContent = ctx.getContent();
// return dropContent;
}
public void writeMigration(File file) {
currentModel().writeMigration(file);
@@ -166,22 +139,6 @@ public class DdlGenerator implements SpiEbeanPlugin {
} catch (IOException e) {
throw new RuntimeException(e);
}
// DdlGenContext ctx = createContext();
// CreateTableVisitor create = new CreateTableVisitor(ctx);
// VisitorUtil.visit(server, create);
//
// CreateSequenceVisitor createSequence = new CreateSequenceVisitor(ctx);
// VisitorUtil.visit(server, createSequence);
//
// AddForeignKeysVisitor fkeys = new AddForeignKeysVisitor(true, ctx);
// VisitorUtil.visit(server, fkeys);
//
// CreateIndexVisitor indexes = new CreateIndexVisitor(ctx);
// VisitorUtil.visit(server, indexes);
//
// ctx.flush();
// createContent = ctx.getContent();
// return createContent;
}
protected String getDropFileName() {
@@ -192,12 +149,6 @@ public class DdlGenerator implements SpiEbeanPlugin {
return server.getName() + "-create.sql";
}
protected DdlGenContext createContext() {
return new DdlGenContext(dbPlatform, namingConvention);
}
protected CurrentModel currentModel() {
if (currentModel == null) {
currentModel = new CurrentModel(server);
@@ -1,69 +0,0 @@
package com.avaje.ebeaninternal.server.ddl;
import com.avaje.ebean.config.dbplatform.DbDdlSyntax;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Used to generate the drop table DDL script.
*/
public class DropSequenceVisitor implements BeanVisitor {
private static final Logger logger = LoggerFactory.getLogger(DropSequenceVisitor.class);
private final DdlGenContext ctx;
private final DbDdlSyntax ddlSyntax;
private final boolean supportsSequence;
public DropSequenceVisitor(DdlGenContext ctx) {
this.ctx = ctx;
this.ddlSyntax = ctx.getDdlSyntax();
this.supportsSequence = ctx.getDbPlatform().getDbIdentity().isSupportsSequence();
}
public boolean visitBean(BeanDescriptor<?> descriptor) {
if (!descriptor.isInheritanceRoot()){
return false;
}
if (descriptor.getSequenceName() != null) {
if (!supportsSequence){
// Hopefully a generic test case
String msg = "Not dropping sequence "+descriptor.getSequenceName()+" on Bean "+descriptor.getName()
+" as DatabasePlatform does not support sequences";
logger.trace(msg);
return false;
}
ctx.write("drop sequence ");
if (ddlSyntax.getDropIfExists() != null){
ctx.write(ddlSyntax.getDropIfExists()).write(" ");
}
ctx.write(descriptor.getSequenceName());
ctx.write(";").writeNewLine().writeNewLine();
}
return true;
}
public void visitBeanEnd(BeanDescriptor<?> descriptor) {
}
public void visitBegin() {
}
public void visitEnd() {
}
public PropertyVisitor visitProperty(BeanProperty p) {
// Return null as we are not interested in properties
return null;
}
}
@@ -1,89 +0,0 @@
package com.avaje.ebeaninternal.server.ddl;
import com.avaje.ebean.config.dbplatform.DbDdlSyntax;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
/**
* Used to generate the drop table DDL script.
*/
public class DropTableVisitor implements BeanVisitor {
final DdlGenContext ctx;
final DbDdlSyntax ddlSyntax;
public DropTableVisitor(DdlGenContext ctx) {
this.ctx = ctx;
this.ddlSyntax = ctx.getDdlSyntax();
}
protected void writeDropTable(BeanDescriptor<?> descriptor){
writeDropTable(descriptor.getBaseTable());
}
protected void writeDropTable(String tableName){
ctx.write(ddlSyntax.dropTablePrefix(tableName));
ctx.write("drop table ");
if (ddlSyntax.getDropIfExists() != null){
ctx.write(ddlSyntax.getDropIfExists()).write(" ");
}
ctx.write(tableName);
if (ddlSyntax.getDropTableCascade() != null){
ctx.write(" ").write(ddlSyntax.getDropTableCascade());
}
ctx.write(";").writeNewLine().writeNewLine();
}
public boolean visitBean(BeanDescriptor<?> descriptor) {
if (!descriptor.isInheritanceRoot()){
return false;
}
writeDropTable(descriptor);
dropIntersectionTables(descriptor);
return true;
}
private void dropIntersectionTables(BeanDescriptor<?> descriptor) {
BeanPropertyAssocMany<?>[] manyProps = descriptor.propertiesMany();
for (int i = 0; i < manyProps.length; i++) {
if (manyProps[i].isManyToMany()){
String intTable = manyProps[i].getIntersectionTableJoin().getTable();
if (ctx.isProcessIntersectionTable(intTable)) {
writeDropTable(intTable);
}
}
}
}
public void visitBeanEnd(BeanDescriptor<?> descriptor) {
}
public void visitBegin() {
if (ddlSyntax.getDisableReferentialIntegrity() != null){
ctx.write(ddlSyntax.getDisableReferentialIntegrity());
ctx.write(";").writeNewLine().writeNewLine();
}
}
public void visitEnd() {
if (ddlSyntax.getEnableReferentialIntegrity() != null){
ctx.write(ddlSyntax.getEnableReferentialIntegrity());
ctx.write(";").writeNewLine().writeNewLine();
}
}
public PropertyVisitor visitProperty(BeanProperty p) {
// Return null as we are not interested in properties
return null;
}
}
@@ -1,53 +0,0 @@
package com.avaje.ebeaninternal.server.ddl;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
/**
* Used to visit a BeanProperty given the type of bean property it is.
*/
public interface PropertyVisitor {
/**
* Visit a OneToMany or ManyToMany property.
*/
void visitMany(BeanPropertyAssocMany<?> p);
/**
* Visit the imported side of a OneToOne property.
*/
void visitOneImported(BeanPropertyAssocOne<?> p);
/**
* Visit the exported side of a OneToOne property.
*/
void visitOneExported(BeanPropertyAssocOne<?> p);
/**
* Visit an embedded property.
*/
void visitEmbedded(BeanPropertyAssocOne<?> p);
/**
* Visit the scalar property of an embedded bean.
*/
void visitEmbeddedScalar(BeanProperty p, BeanPropertyAssocOne<?> embedded);
/**
* Visit a scalar property.
*/
void visitScalar(BeanProperty p);
/**
* Visit a compound value object.
*/
void visitCompound(BeanPropertyCompound p);
/**
* Visit the scalar value inside a compound value object.
*/
void visitCompoundScalar(BeanPropertyCompound compound, BeanProperty p);
}
@@ -1,125 +0,0 @@
package com.avaje.ebeaninternal.server.ddl;
import java.util.List;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
/**
* Utility object to use BeanVisitor.
*/
public class VisitorUtil {
/**
* Visit all the descriptors for a given server.
*/
public static void visit(SpiEbeanServer server, BeanVisitor visitor){
visit(server.getBeanDescriptors(), visitor);
}
/**
* Visit all the descriptors in the list.
*/
public static void visit(List<BeanDescriptor<?>> descriptors, BeanVisitor visitor){
visitor.visitBegin();
for (BeanDescriptor<?> desc : descriptors) {
if (desc.getBaseTable() != null){
visitBean(desc, visitor);
}
}
visitor.visitEnd();
}
/**
* Visit the bean using a visitor.
*/
public static void visitBean(BeanDescriptor<?> desc, BeanVisitor visitor) {
if (visitor.visitBean(desc)) {
BeanProperty idProp = desc.getIdProperty();
if (idProp != null) {
visit(visitor, idProp);
}
BeanPropertyAssocOne<?> unidirectional = desc.getUnidirectional();
if (unidirectional != null) {
visit(visitor, unidirectional);
}
BeanProperty[] propertiesNonTransient = desc.propertiesNonTransient();
for (int i = 0; i < propertiesNonTransient.length; i++) {
BeanProperty p = propertiesNonTransient[i];
if (!p.isFormula() && !p.isSecondaryTable()) {
visit(visitor, p);
}
}
visitor.visitBeanEnd(desc);
}
}
private static void visit(BeanVisitor visitor, BeanProperty p) {
PropertyVisitor pv = visitor.visitProperty(p);
if (pv != null) {
visit(p, pv);
}
}
/**
* Visit all the properties.
*/
public static void visit(BeanProperty[] p, PropertyVisitor pv){
for (int i = 0; i < p.length; i++) {
visit(p[i], pv);
}
}
/**
* Visit the property.
*/
public static void visit(BeanProperty p, PropertyVisitor pv) {
if (p instanceof BeanPropertyAssocMany<?>){
pv.visitMany((BeanPropertyAssocMany<?>)p);
} else if (p instanceof BeanPropertyAssocOne<?>){
BeanPropertyAssocOne<?> assocOne = (BeanPropertyAssocOne<?>)p;
if (assocOne.isEmbedded()){
pv.visitEmbedded(assocOne);
BeanProperty[] embProps = assocOne.getProperties();
for (int i = 0; i < embProps.length; i++) {
pv.visitEmbeddedScalar(embProps[i], assocOne);
}
} else if (assocOne.isOneToOneExported()){
pv.visitOneExported(assocOne);
} else {
pv.visitOneImported(assocOne);
}
} else if (p instanceof BeanPropertyCompound){
BeanPropertyCompound compound = (BeanPropertyCompound)p;
pv.visitCompound(compound);
BeanProperty[] properties = compound.getScalarProperties();
for (int i = 0; i < properties.length; i++) {
pv.visitCompoundScalar(compound, properties[i]);
}
} else {
pv.visitScalar(p);
}
}
}
@@ -1 +0,0 @@
package com.avaje.ebeaninternal.server.ddl;
+5 -4
View File
@@ -23,6 +23,7 @@ ebean.autofetch.traceUsageCollection=false
ebean.ddl.generate=true
ebean.ddl.run=true
datasource.default=h2
ebean.persistBatch=NONE
ebean.persistBatchOnCascade=ALL
@@ -50,7 +51,7 @@ ebean.cacheWarmingDelay=-1
## DataSources (If using default Ebean DataSourceFactory)
## -------------------------------------------------------------
datasource.default=ora
datasource.h2.username=sa
datasource.h2.password=
@@ -96,9 +97,9 @@ datasource.hsqldb.databaseUrl=jdbc:hsqldb:mem:tests
datasource.hsqldb.databaseDriver=org.hsqldb.jdbcDriver
datasource.mysql.username=test
datasource.mysql.password=test
datasource.mysql.databaseUrl=jdbc:mysql://127.0.0.1:3306/test
datasource.mysql.username=unit
datasource.mysql.password=unit
datasource.mysql.databaseUrl=jdbc:mysql://127.0.0.1:3306/unit
datasource.mysql.databaseDriver=com.mysql.jdbc.Driver