Author: max.andersen(a)jboss.com
Date: 2006-10-12 13:23:59 -0400 (Thu, 12 Oct 2006)
New Revision: 10573
Added:
trunk/HibernateExt/tools/src/java/org/hibernate/tool/ant/HbmLintExporterTask.java
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/HbmLintExporter.java
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/Detector.java
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/HbmLint.java
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/Issue.java
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/IssueCollector.java
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/BadCachingDetector.java
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/EntityModelDetector.java
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/InstrumentationDetector.java
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/RelationalModelDetector.java
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/SchemaByMetaDataDetector.java
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/ShadowedIdentifierDetector.java
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/TableSelectorStrategy.java
trunk/HibernateExt/tools/src/templates/lint/text-report.ftl
trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/IncrementalSchemaReadingTest.java
trunk/HibernateExt/tools/src/testsupport/SchemaIssues.hbm.xml
Modified:
trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/JDBCReader.java
trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/SchemaSelection.java
trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/dialect/JDBCMetaDataDialect.java
trunk/HibernateExt/tools/src/java/org/hibernate/tool/ant/Hbm2CfgXmlExporterTask.java
trunk/HibernateExt/tools/src/java/org/hibernate/tool/ant/Hbm2DocExporterTask.java
trunk/HibernateExt/tools/src/java/org/hibernate/tool/ant/HibernateToolTask.java
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/GenericExporter.java
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/pojo/EntityPOJOClass.java
trunk/HibernateExt/tools/src/test/org/hibernate/tool/JDBCMetaDataBinderTestCase.java
trunk/HibernateExt/tools/src/test/org/hibernate/tool/ToolAllTests.java
trunk/HibernateExt/tools/src/test/org/hibernate/tool/ant/HibernateToolTest.java
trunk/HibernateExt/tools/src/testsupport/anttest-build.xml
Log:
Modified: trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/JDBCReader.java
===================================================================
--- trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/JDBCReader.java 2006-10-12
17:23:52 UTC (rev 10572)
+++ trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/JDBCReader.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -1,8 +1,12 @@
package org.hibernate.cfg.reveng;
+import java.sql.Connection;
import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
import java.sql.SQLException;
+import java.sql.Statement;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
@@ -19,6 +23,7 @@
import org.hibernate.cfg.JDBCBinderException;
import org.hibernate.cfg.reveng.dialect.MetaDataDialect;
import org.hibernate.connection.ConnectionProvider;
+import org.hibernate.dialect.Dialect;
import org.hibernate.exception.SQLExceptionConverter;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.ForeignKey;
@@ -55,7 +60,7 @@
}
}
- public DatabaseCollector readDatabaseSchema(DatabaseCollector dbs, String catalog,
String schema, ProgressListener progress) {
+ public List readDatabaseSchema(DatabaseCollector dbs, String catalog, String schema,
ProgressListener progress) {
try {
getMetaDataDialect().configure(provider, sec);
revengStrategy.configure(provider, sec);
@@ -63,16 +68,17 @@
Set hasIndices = new HashSet();
List schemaSelectors = revengStrategy.getSchemaSelections();
+ List foundTables = new ArrayList();
if(schemaSelectors==null) {
- processTables(dbs, new SchemaSelection(catalog, schema), hasIndices, progress);
+ foundTables.addAll( processTables(dbs, new SchemaSelection(catalog, schema),
hasIndices, progress) );
} else {
for (Iterator iter = schemaSelectors.iterator(); iter.hasNext();) {
SchemaSelection selection = (SchemaSelection) iter.next();
- processTables(dbs, selection, hasIndices, progress);
+ foundTables.addAll( processTables(dbs, selection, hasIndices, progress) );
}
}
- Iterator tables = dbs.iterateTables();
+ Iterator tables = foundTables.iterator(); // not dbs.iterateTables() to avoid
"double-read" of columns etc.
while ( tables.hasNext() ) {
Table table = (Table) tables.next();
processBasicColumns(table, progress);
@@ -82,33 +88,45 @@
}
}
- tables = dbs.iterateTables();
- List fks = new ArrayList();
- while ( tables.hasNext() ) {
- Table table = (Table) tables.next();
- // Done here after the basic process of collections as we might not have touched
- // all referenced tables (this ensure the columns are the same instances througout
the basic JDBC derived model.
- // after this stage it should be "ok" to divert from keeping columns in
sync as it can be required if the same
- //column is used with different aliases in the ORM mapping.
- ForeignKeysInfo foreignKeys = processForeignKeys(dbs, table, progress);
- fks.add( foreignKeys );
- }
+ tables = foundTables.iterator(); //dbs.iterateTables();
+ Map oneToManyCandidates = resolveForeignKeys( dbs, tables, progress );
- Map oneToManyCandidates = new HashMap();
- for (Iterator iter = fks.iterator(); iter.hasNext();) {
- ForeignKeysInfo element = (ForeignKeysInfo) iter.next();
- Map map = element.process( revengStrategy );
- mergeMultiMap( oneToManyCandidates, map );
- }
-
dbs.setOneToManyCandidates(oneToManyCandidates);
- return dbs;
+ return foundTables;
} finally {
getMetaDataDialect().close();
revengStrategy.close();
}
}
+
+ /**
+ * Iterates the tables and find all the foreignkeys that refers to something that is
available inside the DatabaseCollector.
+ * @param dbs
+ * @param progress
+ * @param tables
+ * @return
+ */
+ private Map resolveForeignKeys(DatabaseCollector dbs, Iterator tables, ProgressListener
progress) {
+ List fks = new ArrayList();
+ while ( tables.hasNext() ) {
+ Table table = (Table) tables.next();
+ // Done here after the basic process of collections as we might not have touched
+ // all referenced tables (this ensure the columns are the same instances througout the
basic JDBC derived model.
+ // after this stage it should be "ok" to divert from keeping columns in sync
as it can be required if the same
+ //column is used with different aliases in the ORM mapping.
+ ForeignKeysInfo foreignKeys = processForeignKeys(dbs, table, progress);
+ fks.add( foreignKeys );
+ }
+
+ Map oneToManyCandidates = new HashMap();
+ for (Iterator iter = fks.iterator(); iter.hasNext();) {
+ ForeignKeysInfo element = (ForeignKeysInfo) iter.next();
+ Map map = element.process( revengStrategy ); // the actual foreignkey is created
here.
+ mergeMultiMap( oneToManyCandidates, map );
+ }
+ return oneToManyCandidates;
+ }
static class ForeignKeysInfo {
@@ -416,7 +434,7 @@
return value.equals(tf);
}
- private void processTables(DatabaseCollector dbs, SchemaSelection schemaSelection, Set
hasIndices, ProgressListener progress) {
+ private Collection processTables(DatabaseCollector dbs, SchemaSelection schemaSelection,
Set hasIndices, ProgressListener progress) {
Map tableRs = null;
Iterator tableIterator = null;
List tables = new ArrayList();
@@ -465,6 +483,7 @@
}
}
+ List processedTables = new ArrayList();
tableIterator = tables.iterator();
while (tableIterator.hasNext() ) {
tableRs = (Map) tableIterator.next();
@@ -503,6 +522,7 @@
if(tableType.equals("TABLE")) {
hasIndices.add(table);
}
+ processedTables.add( table );
}
else {
log.debug("Ignoring table " + tableName + " of type " +
tableType);
@@ -510,6 +530,7 @@
}
}
+ return processedTables;
}
private void processBasicColumns(Table table, ProgressListener progress) {
@@ -803,7 +824,7 @@
}
}
- public DatabaseCollector readDatabaseSchema(DatabaseCollector dbs, String catalog,
String schema) {
+ public List readDatabaseSchema(DatabaseCollector dbs, String catalog, String schema) {
return readDatabaseSchema(dbs, catalog, schema, new NoopProgressListener());
}
@@ -827,5 +848,44 @@
protected String getSchemaForDBLookup(String schema) {
return schema==null?defaultSchema:schema;
- }
-}
+ }
+
+ public Set readSequences(String sql) {
+ Set sequences = new HashSet();
+ if (sql!=null) {
+ Connection connection = null;
+ try {
+
+ connection = provider.getConnection();
+ Statement statement = null;
+ ResultSet rs = null;
+ try {
+ statement = connection.createStatement();
+ rs = statement.executeQuery(sql);
+
+ while ( rs.next() ) {
+ sequences.add( rs.getString(1).toLowerCase().trim() );
+ }
+ }
+ finally {
+ if (rs!=null) rs.close();
+ if (statement!=null) statement.close();
+ }
+
+ } catch (SQLException e) {
+ sec.convert(e, "Problem while closing connection", null);
+ }
+ finally {
+ if(connection!=null)
+ try {
+ provider.closeConnection( connection );
+ }
+ catch (SQLException e) {
+ sec.convert(e, "Problem while closing connection", null);
+ }
+ }
+ }
+ return sequences;
+ }
+}
+
Modified: trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/SchemaSelection.java
===================================================================
---
trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/SchemaSelection.java 2006-10-12
17:23:52 UTC (rev 10572)
+++
trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/SchemaSelection.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -5,16 +5,20 @@
String matchCatalog;
String matchSchema;
String matchTable;
-
- public SchemaSelection(String catalog, String schema) {
+
+ public SchemaSelection(String catalog, String schema, String table) {
matchCatalog = catalog;
matchSchema = schema;
+ matchTable = table;
}
- public SchemaSelection() {
-
+ public SchemaSelection(String catalog, String schema) {
+ this(catalog, schema, null);
}
+ public SchemaSelection() { }
+
+
public String getMatchCatalog() {
return matchCatalog;
}
Modified:
trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/dialect/JDBCMetaDataDialect.java
===================================================================
---
trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/dialect/JDBCMetaDataDialect.java 2006-10-12
17:23:52 UTC (rev 10572)
+++
trunk/HibernateExt/tools/src/java/org/hibernate/cfg/reveng/dialect/JDBCMetaDataDialect.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -7,9 +7,7 @@
import java.util.Iterator;
import java.util.Map;
-import org.hibernate.cfg.JDBCBinderException;
import org.hibernate.mapping.Table;
-import org.hibernate.util.StringHelper;
/**
* MetaData dialect that uses standard JDBC for reading metadata.
Modified:
trunk/HibernateExt/tools/src/java/org/hibernate/tool/ant/Hbm2CfgXmlExporterTask.java
===================================================================
---
trunk/HibernateExt/tools/src/java/org/hibernate/tool/ant/Hbm2CfgXmlExporterTask.java 2006-10-12
17:23:52 UTC (rev 10572)
+++
trunk/HibernateExt/tools/src/java/org/hibernate/tool/ant/Hbm2CfgXmlExporterTask.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -24,7 +24,7 @@
}
public String getName() {
- return "cfg2cfgxml (Generates hibernate.cfg.xml)";
+ return "hbm2cfgxml (Generates hibernate.cfg.xml)";
}
protected Exporter configureExporter(Exporter exporter) {
Modified:
trunk/HibernateExt/tools/src/java/org/hibernate/tool/ant/Hbm2DocExporterTask.java
===================================================================
---
trunk/HibernateExt/tools/src/java/org/hibernate/tool/ant/Hbm2DocExporterTask.java 2006-10-12
17:23:52 UTC (rev 10572)
+++
trunk/HibernateExt/tools/src/java/org/hibernate/tool/ant/Hbm2DocExporterTask.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -14,7 +14,7 @@
}
public String getName() {
- return "cfg2doc (Generates html schema documentation)";
+ return "hbm2doc (Generates html schema documentation)";
}
protected Exporter createExporter() {
Added: trunk/HibernateExt/tools/src/java/org/hibernate/tool/ant/HbmLintExporterTask.java
===================================================================
---
trunk/HibernateExt/tools/src/java/org/hibernate/tool/ant/HbmLintExporterTask.java 2006-10-12
17:23:52 UTC (rev 10572)
+++
trunk/HibernateExt/tools/src/java/org/hibernate/tool/ant/HbmLintExporterTask.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -0,0 +1,21 @@
+package org.hibernate.tool.ant;
+
+import org.hibernate.tool.hbm2x.Exporter;
+import org.hibernate.tool.hbm2x.HbmLintExporter;
+
+public class HbmLintExporterTask extends ExporterTask {
+
+ public HbmLintExporterTask(HibernateToolTask parent) {
+ super( parent );
+ }
+
+ protected Exporter createExporter() {
+ return new HbmLintExporter();
+ }
+
+
+ String getName() {
+ return "hbmlint (scans mapping for errors)";
+ }
+
+}
Modified: trunk/HibernateExt/tools/src/java/org/hibernate/tool/ant/HibernateToolTask.java
===================================================================
---
trunk/HibernateExt/tools/src/java/org/hibernate/tool/ant/HibernateToolTask.java 2006-10-12
17:23:52 UTC (rev 10572)
+++
trunk/HibernateExt/tools/src/java/org/hibernate/tool/ant/HibernateToolTask.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -129,6 +129,13 @@
return generator;
}
+ public HbmLintExporterTask createHbmLint() {
+ HbmLintExporterTask generator = new HbmLintExporterTask(this);
+ generators.add(generator);
+ return generator;
+ }
+
+
/**
* Set the classpath to be used when running the Java class
*
Modified: trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/GenericExporter.java
===================================================================
---
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/GenericExporter.java 2006-10-12
17:23:52 UTC (rev 10572)
+++
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/GenericExporter.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -35,7 +35,7 @@
protected void doStart() {
if(filePattern==null) throw new ExporterException("File pattern not set on "
+ this.getClass());
- if(templateName==null) throw new ExporterException("Template pattern not set on
" + this.getClass());
+ if(templateName==null) throw new ExporterException("Template name not set on
" + this.getClass());
if(filePattern.indexOf("{class-name}")>=0) {
exportClasses();
Added: trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/HbmLintExporter.java
===================================================================
---
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/HbmLintExporter.java 2006-10-12
17:23:52 UTC (rev 10572)
+++
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/HbmLintExporter.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -0,0 +1,38 @@
+package org.hibernate.tool.hbm2x;
+
+import java.io.File;
+
+import org.hibernate.cfg.Configuration;
+import org.hibernate.tool.hbmlint.HbmLint;
+
+public class HbmLintExporter extends GenericExporter {
+
+ private static final String TEXT_REPORT_FTL = "lint/text-report.ftl";
+
+ public HbmLintExporter() {
+ }
+
+ public HbmLintExporter(Configuration cfg, File outputdir) {
+ super(cfg, outputdir);
+
+ }
+
+ public void start() {
+ // TODO: make non-hardwired
+ setFilePattern( "hbmlint-result.txt" );
+ setTemplateName( TEXT_REPORT_FTL );
+ super.start();
+ }
+ protected void setupContext() {
+ HbmLint hbmlint = HbmLint.createInstance();
+ hbmlint.analyze( getConfiguration() );
+ getProperties().put("lintissues", hbmlint.getResults());
+ super.setupContext();
+ }
+
+ public String getName() {
+ return "hbmlint";
+ }
+
+
+}
Modified:
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/pojo/EntityPOJOClass.java
===================================================================
---
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/pojo/EntityPOJOClass.java 2006-10-12
17:23:52 UTC (rev 10572)
+++
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/pojo/EntityPOJOClass.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -505,38 +505,7 @@
.append(", fetch=").append( getFetchType( property ) );
if ( collection.isInverse() ) {
annotation.append(", mappedBy=\"");
- Iterator joinColumnsIt = collection.getKey().getColumnIterator();
- Set joinColumns = new HashSet();
- while ( joinColumnsIt.hasNext() ) {
- joinColumns.add( joinColumnsIt.next() );
- }
- OneToMany oneToMany = (OneToMany) collection.getElement();
- PersistentClass pc = cfg.getClassMapping( oneToMany.getReferencedEntityName() );
- Iterator properties = pc.getPropertyClosureIterator();
- //TODO we should check the table too
- boolean isOtherSide = false;
- mappedBy = "unresolved";
- while ( ! isOtherSide && properties.hasNext() ) {
- Property manyProperty = (Property) properties.next();
- Value manyValue = manyProperty.getValue();
- if ( manyValue != null && manyValue instanceof ManyToOne ) {
- if ( joinColumns.size() == manyValue.getColumnSpan() ) {
- isOtherSide = true;
- Iterator it = manyValue.getColumnIterator();
- while ( it.hasNext() ) {
- Object column = it.next();
- if (! joinColumns.contains( column ) ) {
- isOtherSide = false;
- break;
- }
- }
- if (isOtherSide) {
- mappedBy = manyProperty.getName();
- }
- }
-
- }
- }
+ mappedBy = getOneToManyMappedBy( cfg, collection );
annotation.append( mappedBy ).append("\"");
}
annotation.append(")");
@@ -551,40 +520,7 @@
.append(", fetch=").append( getFetchType( property ) );
if ( collection.isInverse() ) {
annotation.append(", mappedBy=\"");
- Iterator joinColumnsIt = collection.getKey().getColumnIterator();
- Set joinColumns = new HashSet();
- while ( joinColumnsIt.hasNext() ) {
- joinColumns.add( joinColumnsIt.next() );
- }
- ManyToOne manyToOne = (ManyToOne) collection.getElement();
- PersistentClass pc = cfg.getClassMapping( manyToOne.getReferencedEntityName() );
- Iterator properties = pc.getPropertyClosureIterator();
- //TODO we should check the table too
- boolean isOtherSide = false;
- mappedBy = "unresolved";
- while ( ! isOtherSide && properties.hasNext() ) {
- Property collectionProperty = (Property) properties.next();
- Value collectionValue = collectionProperty.getValue();
- if ( collectionValue != null && collectionValue instanceof Collection ) {
- Collection realCollectionValue = (Collection) collectionValue;
- if ( ! realCollectionValue.isOneToMany() ) {
- if ( joinColumns.size() == realCollectionValue.getElement().getColumnSpan() ) {
- isOtherSide = true;
- Iterator it = realCollectionValue.getElement().getColumnIterator();
- while ( it.hasNext() ) {
- Object column = it.next();
- if (! joinColumns.contains( column ) ) {
- isOtherSide = false;
- break;
- }
- }
- if (isOtherSide) {
- mappedBy = collectionProperty.getName();
- }
- }
- }
- }
- }
+ mappedBy = getManyToManyMappedBy( cfg, collection );
annotation.append( mappedBy ).append("\"");
}
annotation.append(")");
@@ -630,6 +566,82 @@
}
return annotation.toString();
}
+
+ private String getManyToManyMappedBy(Configuration cfg, Collection collection) {
+ String mappedBy;
+ Iterator joinColumnsIt = collection.getKey().getColumnIterator();
+ Set joinColumns = new HashSet();
+ while ( joinColumnsIt.hasNext() ) {
+ joinColumns.add( joinColumnsIt.next() );
+ }
+ ManyToOne manyToOne = (ManyToOne) collection.getElement();
+ PersistentClass pc = cfg.getClassMapping( manyToOne.getReferencedEntityName() );
+ Iterator properties = pc.getPropertyClosureIterator();
+ //TODO we should check the table too
+ boolean isOtherSide = false;
+ mappedBy = "unresolved";
+ while ( ! isOtherSide && properties.hasNext() ) {
+ Property collectionProperty = (Property) properties.next();
+ Value collectionValue = collectionProperty.getValue();
+ if ( collectionValue != null && collectionValue instanceof Collection ) {
+ Collection realCollectionValue = (Collection) collectionValue;
+ if ( ! realCollectionValue.isOneToMany() ) {
+ if ( joinColumns.size() == realCollectionValue.getElement().getColumnSpan() ) {
+ isOtherSide = true;
+ Iterator it = realCollectionValue.getElement().getColumnIterator();
+ while ( it.hasNext() ) {
+ Object column = it.next();
+ if (! joinColumns.contains( column ) ) {
+ isOtherSide = false;
+ break;
+ }
+ }
+ if (isOtherSide) {
+ mappedBy = collectionProperty.getName();
+ }
+ }
+ }
+ }
+ }
+ return mappedBy;
+ }
+
+ private String getOneToManyMappedBy(Configuration cfg, Collection collection) {
+ String mappedBy;
+ Iterator joinColumnsIt = collection.getKey().getColumnIterator();
+ Set joinColumns = new HashSet();
+ while ( joinColumnsIt.hasNext() ) {
+ joinColumns.add( joinColumnsIt.next() );
+ }
+ OneToMany oneToMany = (OneToMany) collection.getElement();
+ PersistentClass pc = cfg.getClassMapping( oneToMany.getReferencedEntityName() );
+ Iterator properties = pc.getPropertyClosureIterator();
+ //TODO we should check the table too
+ boolean isOtherSide = false;
+ mappedBy = "unresolved";
+ while ( ! isOtherSide && properties.hasNext() ) {
+ Property manyProperty = (Property) properties.next();
+ Value manyValue = manyProperty.getValue();
+ if ( manyValue != null && manyValue instanceof ManyToOne ) {
+ if ( joinColumns.size() == manyValue.getColumnSpan() ) {
+ isOtherSide = true;
+ Iterator it = manyValue.getColumnIterator();
+ while ( it.hasNext() ) {
+ Object column = it.next();
+ if (! joinColumns.contains( column ) ) {
+ isOtherSide = false;
+ break;
+ }
+ }
+ if (isOtherSide) {
+ mappedBy = manyProperty.getName();
+ }
+ }
+
+ }
+ }
+ return mappedBy;
+ }
public boolean isSubclass() {
return clazz.getSuperclass()!=null;
Added: trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/Detector.java
===================================================================
--- trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/Detector.java 2006-10-12
17:23:52 UTC (rev 10572)
+++ trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/Detector.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -0,0 +1,29 @@
+package org.hibernate.tool.hbmlint;
+
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Settings;
+
+public abstract class Detector {
+
+ private Configuration cfg;
+ private Settings settings;
+
+ public void initialize(Configuration cfg, Settings settings) {
+ this.cfg = cfg;
+ this.settings = settings;
+ }
+
+ protected Settings getSettings() {
+ return settings;
+ }
+
+ protected Configuration getConfiguration() {
+ return cfg;
+ }
+
+ public void visit(Configuration cfg, IssueCollector collector) {
+
+ }
+
+ abstract public String getName();
+}
Added: trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/HbmLint.java
===================================================================
--- trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/HbmLint.java 2006-10-12
17:23:52 UTC (rev 10572)
+++ trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/HbmLint.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -0,0 +1,57 @@
+package org.hibernate.tool.hbmlint;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Settings;
+import org.hibernate.tool.hbmlint.detector.BadCachingDetector;
+import org.hibernate.tool.hbmlint.detector.InstrumentationDetector;
+import org.hibernate.tool.hbmlint.detector.SchemaByMetaDataDetector;
+import org.hibernate.tool.hbmlint.detector.ShadowedIdentifierDetector;
+
+public class HbmLint implements IssueCollector {
+
+
+ final Detector[] detectors;
+
+ public HbmLint(Detector[] detectors) {
+ this.detectors = detectors;
+ }
+
+ List results = new ArrayList();
+
+ public void analyze(Configuration cfg) {
+
+ Settings settings = cfg.buildSettings();
+
+ for (int i = 0; i < detectors.length; i++) {
+ detectors[i].initialize( cfg, settings );
+ detectors[i].visit(cfg, this);
+ }
+
+ }
+
+ /* (non-Javadoc)
+ * @see
org.hibernate.tool.hbmlint.IssueCollector#reportProblem(org.hibernate.tool.hbmlint.Issue)
+ */
+ public void reportIssue(Issue analyze) {
+ results.add(analyze);
+ }
+
+ public List getResults() {
+ return results;
+ }
+
+ public static HbmLint createInstance() {
+ return new HbmLint(
+ new Detector[] {
+ new BadCachingDetector(),
+ new InstrumentationDetector(),
+ new ShadowedIdentifierDetector(),
+ new SchemaByMetaDataDetector()
+ });
+
+ }
+
+}
Added: trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/Issue.java
===================================================================
--- trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/Issue.java 2006-10-12
17:23:52 UTC (rev 10572)
+++ trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/Issue.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -0,0 +1,27 @@
+package org.hibernate.tool.hbmlint;
+
+public class Issue {
+
+ public static final int HIGH_PRIORITY = 100;
+ public static final int NORMAL_PRIORITY = 50;
+ public static final int LOW_PRIORITY = 0;
+
+ private final String type;
+ private final int priority;
+
+ private final String description;
+
+ public Issue(String type, int priority, String description) {
+ this.description = description;
+ this.priority = priority;
+ this.type = type;
+ }
+
+ public String toString() {
+ return type + ":" + description;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+}
Added: trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/IssueCollector.java
===================================================================
---
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/IssueCollector.java 2006-10-12
17:23:52 UTC (rev 10572)
+++
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/IssueCollector.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -0,0 +1,7 @@
+package org.hibernate.tool.hbmlint;
+
+public interface IssueCollector {
+
+ public abstract void reportIssue(Issue analyze);
+
+}
\ No newline at end of file
Added:
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/BadCachingDetector.java
===================================================================
---
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/BadCachingDetector.java 2006-10-12
17:23:52 UTC (rev 10572)
+++
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/BadCachingDetector.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -0,0 +1,36 @@
+package org.hibernate.tool.hbmlint.detector;
+
+import org.hibernate.cfg.Configuration;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.mapping.Value;
+import org.hibernate.tool.hbm2x.visitor.EntityNameFromValueVisitor;
+import org.hibernate.tool.hbmlint.Issue;
+import org.hibernate.tool.hbmlint.IssueCollector;
+
+public class BadCachingDetector extends EntityModelDetector {
+
+ public String getName() {
+ return "cache";
+ }
+ public void visitProperty(Configuration configuration, PersistentClass clazz, Property
property, IssueCollector collector) {
+ Value value = property.getValue();
+
+ if(value instanceof Collection) {
+ Collection col = (Collection) value;
+ if(col.getCacheConcurrencyStrategy()!=null) { // caching is enabled
+ if (!col.getElement().isSimpleValue()) {
+ String entityName = (String) col.getElement().accept( new
EntityNameFromValueVisitor() );
+
+ if(entityName!=null) {
+ PersistentClass classMapping = configuration.getClassMapping( entityName );
+ if(classMapping.getCacheConcurrencyStrategy()==null) {
+ collector.reportIssue( new Issue("CACHE_COLLECTION_NONCACHABLE_TARGET",
Issue.HIGH_PRIORITY, "Entity '" + classMapping.getEntityName() +"'
is referenced from the cache-enabled collection '" + col.getRole() + "'
without the entity being cachable"));
+ }
+ }
+ }
+ }
+ }
+ }
+}
Added:
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/EntityModelDetector.java
===================================================================
---
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/EntityModelDetector.java 2006-10-12
17:23:52 UTC (rev 10572)
+++
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/EntityModelDetector.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -0,0 +1,39 @@
+package org.hibernate.tool.hbmlint.detector;
+
+import java.util.Iterator;
+
+import org.hibernate.cfg.Configuration;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.tool.hbmlint.Detector;
+import org.hibernate.tool.hbmlint.IssueCollector;
+
+public abstract class EntityModelDetector extends Detector {
+
+ public void visit(Configuration cfg, IssueCollector collector) {
+ for (Iterator iter = cfg.getClassMappings(); iter.hasNext();) {
+ PersistentClass clazz = (PersistentClass) iter.next();
+ this.visit(cfg, clazz, collector);
+ }
+ }
+
+ public void visit(Configuration cfg, PersistentClass clazz, IssueCollector collector) {
+ visitProperties( cfg, clazz, collector );
+ }
+
+ public void visitProperties(Configuration cfg, PersistentClass clazz, IssueCollector
collector) {
+ if(clazz.hasIdentifierProperty()) {
+ this.visitProperty(getConfiguration(), clazz, clazz.getIdentifierProperty(),
collector);
+ }
+ Iterator propertyIterator = clazz.getPropertyIterator();
+ while ( propertyIterator.hasNext() ) {
+ Property property = (Property) propertyIterator.next();
+ this.visitProperty(getConfiguration(), clazz, property, collector);
+
+ }
+ }
+
+ public void visitProperty(Configuration configuration, PersistentClass clazz, Property
property, IssueCollector collector) {
+
+ }
+}
Added:
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/InstrumentationDetector.java
===================================================================
---
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/InstrumentationDetector.java 2006-10-12
17:23:52 UTC (rev 10572)
+++
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/InstrumentationDetector.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -0,0 +1,81 @@
+package org.hibernate.tool.hbmlint.detector;
+
+import org.hibernate.MappingException;
+import org.hibernate.bytecode.cglib.BytecodeProviderImpl;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.cfg.Settings;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.tool.hbmlint.Issue;
+import org.hibernate.tool.hbmlint.IssueCollector;
+
+public class InstrumentationDetector extends EntityModelDetector {
+
+ public String getName() {
+ return "instrument";
+ }
+ private boolean cglibEnabled;
+ private boolean javassistEnabled;
+
+ public void initialize(Configuration cfg, Settings settings) {
+ super.initialize( cfg, settings );
+
+ cglibEnabled = false;
+ javassistEnabled = false;
+
+ if(Environment.getBytecodeProvider() instanceof BytecodeProviderImpl) {
+ cglibEnabled = true;
+ } else if(Environment.getBytecodeProvider() instanceof BytecodeProviderImpl) {
+ javassistEnabled = true;
+ }
+ }
+
+ public void visit(Configuration cfg, PersistentClass clazz, IssueCollector collector) {
+ Class mappedClass;
+
+
+ try {
+ mappedClass = clazz.getMappedClass();
+ } catch(MappingException me) {
+ // ignore
+ return;
+ }
+
+ if(clazz.isLazy()) {
+ try {
+ mappedClass.getConstructor( new Class[0] );
+ }
+ catch (SecurityException e) {
+ // ignore
+ }
+ catch (NoSuchMethodException e) {
+ collector.reportIssue(new
Issue("LAZY_NO_DEFAULT_CONSTRUCTOR",Issue.NORMAL_PRIORITY,
"lazy='true' set for '" + clazz.getEntityName() +"', but
class has no default constructor." ));
+ return;
+ }
+
+ } else if(cglibEnabled || javassistEnabled){
+ Class[] interfaces = mappedClass.getInterfaces();
+ boolean cglib = false;
+ boolean javaassist = false;
+ for (int i = 0; i < interfaces.length; i++) {
+ Class intface = interfaces[i];
+ if(intface.getName().equals(
"net.sf.cglib.transform.impl.InterceptFieldEnabled" )) {
+ cglib = true;
+ } else if(javassistEnabled && !intface.getName().equals(
"org.hibernate.bytecode.javassist.FieldHandled" )) {
+ javaassist = true;
+ }
+ }
+
+ if(cglibEnabled && !cglib) {
+ collector.reportIssue( new Issue("LAZY_NOT_INSTRUMENTED",
Issue.HIGH_PRIORITY, "'" + clazz.getEntityName() + "' has
lazy='false', but its class '" + mappedClass.getName() + "' has
not been instrumented with cglib") );
+ return;
+ } else if (javassistEnabled && !javaassist) {
+ collector.reportIssue( new Issue("LAZY_NOT_INSTRUMENTED",
Issue.HIGH_PRIORITY, "'" + clazz.getEntityName() + "' has
lazy='false', but its class '" + mappedClass.getName() + "' has
not been instrumented with javaassist") );
+ return;
+ } else {
+ // unknown bytecodeprovider...can't really check for that.
+ }
+
+ }
+ }
+}
Added:
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/RelationalModelDetector.java
===================================================================
---
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/RelationalModelDetector.java 2006-10-12
17:23:52 UTC (rev 10572)
+++
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/RelationalModelDetector.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -0,0 +1,41 @@
+package org.hibernate.tool.hbmlint.detector;
+
+import java.util.Iterator;
+
+import org.hibernate.cfg.Configuration;
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.Table;
+import org.hibernate.tool.hbmlint.Detector;
+import org.hibernate.tool.hbmlint.IssueCollector;
+
+public abstract class RelationalModelDetector extends Detector {
+
+ public void visit(Configuration cfg, IssueCollector collector) {
+ for (Iterator iter = cfg.getTableMappings(); iter.hasNext();) {
+ Table table = (Table) iter.next();
+ this.visit(cfg, table, collector);
+ }
+ }
+
+
+ protected void visit(Configuration cfg, Table table, Column col, IssueCollector
collector) {
+
+ }
+
+ protected void visitColumns(Configuration cfg, Table table, IssueCollector collector) {
+ Iterator columnIter = table.getColumnIterator();
+ while ( columnIter.hasNext() ) {
+ Column col = ( Column ) columnIter.next();
+ this.visit( cfg, table, col, collector );
+ }
+ }
+
+ /**
+ * @return true if visit should continue down through the columns
+ */
+ protected void visit(Configuration cfg, Table table, IssueCollector collector) {
+ visitColumns(cfg, table, collector);
+ }
+
+}
+
Added:
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/SchemaByMetaDataDetector.java
===================================================================
---
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/SchemaByMetaDataDetector.java 2006-10-12
17:23:52 UTC (rev 10572)
+++
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/SchemaByMetaDataDetector.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -0,0 +1,266 @@
+package org.hibernate.tool.hbmlint.detector;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeMap;
+
+import org.hibernate.HibernateException;
+import org.hibernate.MappingException;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.cfg.JDBCReaderFactory;
+import org.hibernate.cfg.Settings;
+import org.hibernate.cfg.reveng.DefaultDatabaseCollector;
+import org.hibernate.cfg.reveng.DefaultReverseEngineeringStrategy;
+import org.hibernate.cfg.reveng.JDBCReader;
+import org.hibernate.cfg.reveng.JDBCToHibernateTypeHelper;
+import org.hibernate.cfg.reveng.SchemaSelection;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.Mapping;
+import org.hibernate.id.IdentifierGenerator;
+import org.hibernate.id.PersistentIdentifierGenerator;
+import org.hibernate.mapping.Collection;
+import org.hibernate.mapping.Column;
+import org.hibernate.mapping.IdentifierCollection;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.RootClass;
+import org.hibernate.mapping.Table;
+import org.hibernate.tool.hbmlint.Issue;
+import org.hibernate.tool.hbmlint.IssueCollector;
+import org.hibernate.util.StringHelper;
+
+public class SchemaByMetaDataDetector extends RelationalModelDetector {
+
+ public String getName() {
+ return "schema";
+ }
+
+ JDBCReader reader;
+
+ private TableSelectorStrategy tableSelector;
+
+ private DefaultDatabaseCollector dbc;
+
+ private Dialect dialect;
+
+ private Mapping mapping;
+
+ /** current table as read from the database */
+ Table currentDbTable = null;
+
+ public SchemaByMetaDataDetector() {
+
+ }
+
+ public void initialize(Configuration cfg, Settings settings) {
+ super.initialize( cfg, settings );
+ dialect = settings.getDialect();
+
+ tableSelector = new TableSelectorStrategy(
+ new DefaultReverseEngineeringStrategy() );
+ reader = JDBCReaderFactory.newJDBCReader( cfg.getProperties(),
+ settings, tableSelector );
+ dbc = new DefaultDatabaseCollector();
+ mapping = cfg.buildMapping();
+ }
+
+ public void visit(Configuration cfg, IssueCollector collector) {
+ super.visit( cfg, collector );
+
+ visitGenerators(cfg, collector);
+
+ }
+
+ public void visitGenerators(Configuration cfg, IssueCollector collector) {
+ Iterator iter = iterateGenerators(cfg);
+
+ Set sequences = Collections.EMPTY_SET;
+ if(dialect.supportsSequences()) {
+ sequences = reader.readSequences(dialect.getQuerySequencesString());
+ }
+
+ // TODO: move this check into something that could check per class or collection
instead.
+ while ( iter.hasNext() ) {
+ PersistentIdentifierGenerator generator = (PersistentIdentifierGenerator)
iter.next();
+ Object key = generator.generatorKey();
+ if ( !isSequence(key, sequences) && !isTable( key ) ) {
+ collector.reportIssue( new Issue( "MISSING_ID_GENERATOR",
Issue.HIGH_PRIORITY, "Missing sequence or table: " + key));
+ }
+ }
+
+
+ }
+
+ private boolean isSequence(Object key, Set sequences) {
+ if(key instanceof String) {
+ if ( sequences.contains( key ) ) {
+ return true;
+ } else {
+ String[] strings = StringHelper.split(".", (String) key);
+ if(strings.length==3) {
+ return sequences.contains(strings[2]);
+ } else if (strings.length==2) {
+ return sequences.contains(strings[1]);
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean isTable(Object key) throws HibernateException {
+ // BIG HACK - should probably utilize the table cache before going to the jdbcreader
:(
+ if(key instanceof String) {
+ String[] strings = StringHelper.split(".", (String) key);
+ if(strings.length==1) {
+ tableSelector.clearSchemaSelections();
+ tableSelector.addSchemaSelection( new SchemaSelection(null,null, strings[0]) );
+ List list = reader.readDatabaseSchema( dbc, null, null );
+ return !list.isEmpty();
+ } else if(strings.length==3) {
+ tableSelector.clearSchemaSelections();
+ tableSelector.addSchemaSelection( new SchemaSelection(strings[0],strings[1],
strings[2]) );
+ List list = reader.readDatabaseSchema( dbc, null, null );
+ return !list.isEmpty();
+ } else if (strings.length==2) {
+ tableSelector.clearSchemaSelections();
+ tableSelector.addSchemaSelection( new SchemaSelection(null,strings[0], strings[1])
);
+ List list = reader.readDatabaseSchema( dbc, null, null );
+ return !list.isEmpty();
+ }
+ }
+ return false;
+ }
+
+ public void visit(Configuration cfg, Table table, IssueCollector pc) {
+
+ if ( table.isPhysicalTable() ) {
+ setSchemaSelection( table );
+
+ List list = reader.readDatabaseSchema( dbc, null, null );
+
+ if ( list.isEmpty() ) {
+ pc.reportIssue( new Issue( "SCHEMA_TABLE_MISSING",
+ Issue.HIGH_PRIORITY, "Missing table "
+ + Table.qualify( table.getCatalog(), table
+ .getSchema(), table.getName() ) ) );
+ return;
+ }
+ else if ( list.size() > 1 ) {
+ pc.reportIssue( new Issue( "SCHEMA_TABLE_MISSING",
+ Issue.NORMAL_PRIORITY, "Found "
+ + list.size()
+ + " tables for "
+ + Table.qualify( table.getCatalog(), table
+ .getSchema(), table.getName() ) ) );
+ return;
+ }
+ else {
+ currentDbTable = (Table) list.get( 0 );
+ visitColumns(cfg,table,pc);
+ }
+ }
+ else {
+ // log?
+ }
+ }
+
+ String table(Table t) {
+ return Table.qualify( t.getCatalog(), t.getSchema(), t.getName() );
+ }
+
+ public void visit(Configuration cfg, Table table, Column col,
+ IssueCollector pc) {
+ if ( currentDbTable == null ) {
+ return;
+ }
+
+ Column dbColumn = currentDbTable
+ .getColumn( new Column( col.getName() ) );
+
+ if ( dbColumn == null ) {
+ pc.reportIssue( new Issue( "SCHEMA_COLUMN_MISSING",
+ Issue.HIGH_PRIORITY, table(table) + " is missing column: " + col.getName()
) );
+ }
+ else {
+ //TODO: this needs to be able to know if a type is truly compatible or not. Right now
it requires an exact match.
+ String sqlType = col.getSqlType( dialect, mapping );
+ int dbTypeCode = dbColumn.getSqlTypeCode().intValue();
+ int modelTypeCode = col
+ .getSqlTypeCode( mapping );
+ // TODO: sqltype name string
+ if ( !(dbTypeCode == modelTypeCode ) ) {
+ pc.reportIssue( new Issue( "SCHEMA_COLUMN_TYPE_MISMATCH",
+ Issue.NORMAL_PRIORITY, table(table) + " has a wrong column type for "
+ + col.getName() + ", expected: "
+ + JDBCToHibernateTypeHelper.getJDBCTypeName(modelTypeCode) + " but was
" + JDBCToHibernateTypeHelper.getJDBCTypeName(dbTypeCode) + " in db") );
+ }
+ }
+ }
+
+ private void setSchemaSelection(Table table) {
+ tableSelector.clearSchemaSelections();
+ tableSelector.addSchemaSelection( new SchemaSelection( table
+ .getCatalog(), table.getSchema(), table.getName() ) );
+
+ }
+
+ /**
+ *
+ * @param cfg
+ * @return iterator over all the IdentifierGenerator's found in the entitymodel and
return a list of unique IdentifierGenerators
+ * @throws MappingException
+ */
+ private Iterator iterateGenerators(Configuration cfg) throws MappingException {
+
+ TreeMap generators = new TreeMap();
+ String defaultCatalog = getSettings().getDefaultCatalogName();
+ String defaultSchema = getSettings().getDefaultSchemaName();
+
+ Iterator iter = cfg.getClassMappings();
+ while ( iter.hasNext() ) {
+ PersistentClass pc = (PersistentClass) iter.next();
+
+ if ( !pc.isInherited() ) {
+
+ IdentifierGenerator ig = pc.getIdentifier()
+ .createIdentifierGenerator(
+ dialect,
+ defaultCatalog,
+ defaultSchema,
+ (RootClass) pc
+ );
+
+ if ( ig instanceof PersistentIdentifierGenerator ) {
+ generators.put( ( (PersistentIdentifierGenerator) ig ).generatorKey(), ig );
+ }
+
+ }
+ }
+
+ iter = getConfiguration().getCollectionMappings();
+ while ( iter.hasNext() ) {
+ Collection collection = (Collection) iter.next();
+
+ if ( collection.isIdentified() ) {
+
+ IdentifierGenerator ig = ( (IdentifierCollection) collection ).getIdentifier()
+ .createIdentifierGenerator(
+ dialect,
+ defaultCatalog,
+ defaultSchema,
+ null
+ );
+
+ if ( ig instanceof PersistentIdentifierGenerator ) {
+ generators.put( ( (PersistentIdentifierGenerator) ig ).generatorKey(), ig );
+ }
+
+ }
+ }
+
+ return generators.values().iterator();
+ }
+
+}
Added:
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/ShadowedIdentifierDetector.java
===================================================================
---
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/ShadowedIdentifierDetector.java 2006-10-12
17:23:52 UTC (rev 10572)
+++
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/ShadowedIdentifierDetector.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -0,0 +1,22 @@
+package org.hibernate.tool.hbmlint.detector;
+
+import org.hibernate.cfg.Configuration;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.mapping.Property;
+import org.hibernate.tool.hbmlint.Issue;
+import org.hibernate.tool.hbmlint.IssueCollector;
+
+public class ShadowedIdentifierDetector extends EntityModelDetector {
+
+ public String getName() {
+ return "shadow-id";
+ }
+
+ public void visitProperty(Configuration configuration, PersistentClass clazz, Property
property, IssueCollector collector) {
+ if(property.getName().equals("id")) {
+ if (property != property.getPersistentClass().getIdentifierProperty()) {
+ collector.reportIssue(new Issue("ID_SHADOWED", Issue.LOW_PRIORITY,
property.getPersistentClass().getEntityName() + " has a normal property named
'id'. This can cause issues since HQL queries will always interpret 'id'
as the identifier and not the concrete property"));
+ }
+ }
+ }
+}
Added:
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/TableSelectorStrategy.java
===================================================================
---
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/TableSelectorStrategy.java 2006-10-12
17:23:52 UTC (rev 10572)
+++
trunk/HibernateExt/tools/src/java/org/hibernate/tool/hbmlint/detector/TableSelectorStrategy.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -0,0 +1,33 @@
+/**
+ *
+ */
+package org.hibernate.tool.hbmlint.detector;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.hibernate.cfg.reveng.DelegatingReverseEngineeringStrategy;
+import org.hibernate.cfg.reveng.ReverseEngineeringStrategy;
+import org.hibernate.cfg.reveng.SchemaSelection;
+
+public class TableSelectorStrategy extends DelegatingReverseEngineeringStrategy {
+
+ List selections = new ArrayList();
+
+ public TableSelectorStrategy(ReverseEngineeringStrategy res) {
+ super(res);
+ }
+
+ public List getSchemaSelections() {
+ return selections;
+ }
+
+
+ public void clearSchemaSelections() {
+ selections.clear();
+ }
+
+ public void addSchemaSelection(SchemaSelection selection) {
+ selections.add(selection);
+ }
+}
\ No newline at end of file
Added: trunk/HibernateExt/tools/src/templates/lint/text-report.ftl
===================================================================
--- trunk/HibernateExt/tools/src/templates/lint/text-report.ftl 2006-10-12 17:23:52 UTC
(rev 10572)
+++ trunk/HibernateExt/tools/src/templates/lint/text-report.ftl 2006-10-12 17:23:59 UTC
(rev 10573)
@@ -0,0 +1,3 @@
+<#foreach issue in lintissues>
+${issue}
+</#foreach>
\ No newline at end of file
Modified:
trunk/HibernateExt/tools/src/test/org/hibernate/tool/JDBCMetaDataBinderTestCase.java
===================================================================
---
trunk/HibernateExt/tools/src/test/org/hibernate/tool/JDBCMetaDataBinderTestCase.java 2006-10-12
17:23:52 UTC (rev 10572)
+++
trunk/HibernateExt/tools/src/test/org/hibernate/tool/JDBCMetaDataBinderTestCase.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -139,7 +139,7 @@
protected void tearDown() throws Exception {
executeDDL(getDropSQL(), false);
- assertNoTables();
+
super.tearDown();
}
/**
Modified: trunk/HibernateExt/tools/src/test/org/hibernate/tool/ToolAllTests.java
===================================================================
--- trunk/HibernateExt/tools/src/test/org/hibernate/tool/ToolAllTests.java 2006-10-12
17:23:52 UTC (rev 10572)
+++ trunk/HibernateExt/tools/src/test/org/hibernate/tool/ToolAllTests.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -1,6 +1,7 @@
package org.hibernate.tool;
import org.hibernate.tool.hbm2x.query.QueryAllTests;
+import org.hibernate.tool.hbmlint.HbmLintAllTests;
import org.hibernate.tool.ide.completion.CompletionAllTests;
import junit.framework.Test;
@@ -17,6 +18,6 @@
suite.addTest(org.hibernate.tool.hbm2x.Hbm2XAllTests.suite() );
suite.addTest(CompletionAllTests.suite() );
suite.addTest(QueryAllTests.suite() );
-
+ suite.addTest(HbmLintAllTests.suite() );
return suite;
}}
Modified: trunk/HibernateExt/tools/src/test/org/hibernate/tool/ant/HibernateToolTest.java
===================================================================
---
trunk/HibernateExt/tools/src/test/org/hibernate/tool/ant/HibernateToolTest.java 2006-10-12
17:23:52 UTC (rev 10572)
+++
trunk/HibernateExt/tools/src/test/org/hibernate/tool/ant/HibernateToolTest.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -178,6 +178,15 @@
}
+ public void testHbmLint() {
+ executeTarget("testhbmlint");
+
+ File baseDir = new File(project.getProperty("build.dir"),
"linttest");
+
+ assertTrue(new File(baseDir, "hbmlint-result.txt").exists());
+
+ }
+
public void testNoConfig() {
try {
executeTarget("noconfig-shoulderror");
Added:
trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/IncrementalSchemaReadingTest.java
===================================================================
---
trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/IncrementalSchemaReadingTest.java 2006-10-12
17:23:52 UTC (rev 10572)
+++
trunk/HibernateExt/tools/src/test/org/hibernate/tool/hbm2x/IncrementalSchemaReadingTest.java 2006-10-12
17:23:59 UTC (rev 10573)
@@ -0,0 +1,121 @@
+/*
+ * Created on 2004-12-01
+ *
+ */
+package org.hibernate.tool.hbm2x;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.hibernate.cfg.Environment;
+import org.hibernate.cfg.JDBCMetaDataConfiguration;
+import org.hibernate.cfg.JDBCReaderFactory;
+import org.hibernate.cfg.Settings;
+import org.hibernate.cfg.reveng.DatabaseCollector;
+import org.hibernate.cfg.reveng.DefaultDatabaseCollector;
+import org.hibernate.cfg.reveng.DefaultReverseEngineeringStrategy;
+import org.hibernate.cfg.reveng.JDBCReader;
+import org.hibernate.cfg.reveng.OverrideRepository;
+import org.hibernate.cfg.reveng.SchemaSelection;
+import org.hibernate.cfg.reveng.TableIdentifier;
+import org.hibernate.cfg.reveng.dialect.JDBCMetaDataDialect;
+import org.hibernate.mapping.Table;
+import org.hibernate.tool.JDBCMetaDataBinderTestCase;
+import org.hibernate.tool.hbmlint.detector.TableSelectorStrategy;
+
+
+
+/**
+ * @author max
+ *
+ */
+public class IncrementalSchemaReadingTest extends JDBCMetaDataBinderTestCase {
+
+
+ protected void configure(JDBCMetaDataConfiguration cfg) {
+ super.configure( cfg );
+ }
+
+ public class MockedMetaDataDialect extends JDBCMetaDataDialect {
+ List gottenTables = new ArrayList();
+ public Iterator getTables(String catalog, String schema, String table) {
+ gottenTables.add(table);
+ return super.getTables( catalog, schema, table );
+ }
+
+ }
+
+ public void testReadSchemaIncremental() {
+ Settings buildSettings = cfg.buildSettings();
+ TableSelectorStrategy tss = new TableSelectorStrategy(new
DefaultReverseEngineeringStrategy());
+ MockedMetaDataDialect mockedMetaDataDialect = new MockedMetaDataDialect();
+ JDBCReader reader = JDBCReaderFactory.newJDBCReader( buildSettings, tss,
mockedMetaDataDialect );
+
+ tss.addSchemaSelection( new SchemaSelection(null,null, "CHILD") );
+
+ DatabaseCollector dc = new DefaultDatabaseCollector();
+ reader.readDatabaseSchema( dc, null, null );
+
+ assertEquals(mockedMetaDataDialect.gottenTables.size(),1);
+ assertEquals(mockedMetaDataDialect.gottenTables.get(0),"CHILD");
+
+ Iterator iterator = dc.iterateTables();
+ Table firstChild = (Table) iterator.next();
+ assertEquals(firstChild.getName(), "CHILD");
+ assertFalse(iterator.hasNext());
+
+ assertFalse("should not record foreignkey to table it doesn't know about
yet",firstChild.getForeignKeyIterator().hasNext());
+
+ tss.clearSchemaSelections();
+ tss.addSchemaSelection( new SchemaSelection(null, null, "MASTER") );
+
+ mockedMetaDataDialect.gottenTables.clear();
+ reader.readDatabaseSchema( dc, null, null );
+
+ assertEquals(mockedMetaDataDialect.gottenTables.size(),1);
+ assertEquals(mockedMetaDataDialect.gottenTables.get(0),"MASTER");
+
+
+ iterator = dc.iterateTables();
+ assertNotNull(iterator.next());
+ assertNotNull(iterator.next());
+ assertFalse(iterator.hasNext());
+
+ Table table = dc.getTable( null, null, "CHILD" );
+ assertSame( firstChild, table );
+
+ assertHasNext("should have recorded one foreignkey to child table", 1,
firstChild.getForeignKeyIterator() );
+
+
+ tss.clearSchemaSelections();
+ reader.readDatabaseSchema( dc, null, null );
+
+ Table finalMaster = dc.getTable( null, null, "MASTER" );
+
+ assertSame(firstChild, dc.getTable( null, null, "CHILD" ));
+ assertHasNext( 1, firstChild.getForeignKeyIterator() );
+ assertHasNext( 0, finalMaster.getForeignKeyIterator() );
+
+
+ }
+
+ protected String[] getCreateSQL() {
+
+ return new String[] {
+ "create table master ( id char not null, name varchar(20), primary key (id)
)",
+ "create table child ( childid char not null, masterref char, primary key
(childid), foreign key (masterref) references master(id) )",
+ };
+ }
+
+ protected String[] getDropSQL() {
+
+ return new String[] {
+ "drop table child",
+ "drop table master",
+ };
+ }
+
+}
Added: trunk/HibernateExt/tools/src/testsupport/SchemaIssues.hbm.xml
===================================================================
--- trunk/HibernateExt/tools/src/testsupport/SchemaIssues.hbm.xml 2006-10-12 17:23:52 UTC
(rev 10572)
+++ trunk/HibernateExt/tools/src/testsupport/SchemaIssues.hbm.xml 2006-10-12 17:23:59 UTC
(rev 10573)
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="org.hibernate.tool.hbmlint">
+
+ <class name="Category">
+
+ <id name="id" type="int">
+ <generator class="sequence">
+ <param name="sequence">should_be_there</param>
+ </generator>
+ </id>
+
+ <property name="name" type="string"/>
+
+ </class>
+
+ <class name="BadType">
+
+ <id name="id" type="int">
+ <generator class="hilo"/>
+ </id>
+
+ <property name="name" type="text"/>
+
+ </class>
+
+ <class name="MissingTable">
+ <id name="id" type="long">
+ <generator class="hilo">
+ <param name="table">hilo_table</param>
+ </generator>
+ </id>
+ </class>
+</hibernate-mapping>
Modified: trunk/HibernateExt/tools/src/testsupport/anttest-build.xml
===================================================================
--- trunk/HibernateExt/tools/src/testsupport/anttest-build.xml 2006-10-12 17:23:52 UTC
(rev 10572)
+++ trunk/HibernateExt/tools/src/testsupport/anttest-build.xml 2006-10-12 17:23:59 UTC
(rev 10573)
@@ -436,6 +436,20 @@
<antcall target="afterCfg2hbm" />
</target>
+ <target name="testhbmlint" depends="prepareCfg2hbm"
description="test the query tasks">
+ <taskdef name="hibernatetool"
classname="org.hibernate.tool.ant.HibernateToolTask"
classpathref="tasks.classpath" />
+
+ <hibernatetool destdir="${build.dir}/linttest">
+ <configuration propertyfile="../../etc/hibernate.properties"
configurationfile="querytest-hibernate.cfg.xml">
+ <fileset dir="../test">
+ <include name="**/SchemaIssues.hbm.xml"/>
+ </fileset>
+ </configuration>
+ <hbmlint/>
+ </hibernatetool>
+
+ <antcall target="afterCfg2hbm" />
+ </target>
<target name="noconfig-shoulderror">
<taskdef name="hibernatetool"
classname="org.hibernate.tool.ant.HibernateToolTask"
classpathref="tasks.classpath" />