/*******************************************************************************
* ALMA - Atacama Large Millimeter Array
* Copyright (c) ESO - European Southern Observatory, 2011
* (in the framework of the ALMA collaboration).
* All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*******************************************************************************/
package alma.acs.tmcdb.translator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.hibernate.cfg.reveng.AssociationInfo;
import org.hibernate.cfg.reveng.DefaulAssociationInfo;
import org.hibernate.cfg.reveng.DelegatingReverseEngineeringStrategy;
import org.hibernate.cfg.reveng.ReverseEngineeringStrategy;
import org.hibernate.cfg.reveng.TableIdentifier;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.ForeignKey;
import org.hibernate.mapping.MetaAttribute;
import org.hibernate.tool.hbm2x.MetaAttributeConstants;
import alma.acs.tmcdb.translator.AbstractTableInheritance.CascadeType;
public abstract class AbstractReverseEngineeringStrategy extends DelegatingReverseEngineeringStrategy {
private static final String ORACLE_SEQUENCE = "oracle-sequence";
private static final String IS_XML_CLOB_TYPE = "isXmlClobType";
private static final String HAS_XML_CLOB_TYPE = "hasXmlClobType";
private static final String HAS_ENUM_TYPES = "has-enum-types";
private static final String ENUM_TYPES = "enum-types";
private static final String IS_SUPER_CLASS = "isSuperClass";
private static final String IS_ENUM_TYPE = "is-enum-type";
private static final String ENUM_TYPE_NAME = "enum-type-name";
protected AbstractColumn2Attribute []columnTranslators;
protected AbstractTable2Class []tableTranslators;
protected AbstractTableInheritance []inheritanceTranslators;
/**
* Default constructor, that shouldn't be ever used
*/
public AbstractReverseEngineeringStrategy() { super(null); };
public AbstractReverseEngineeringStrategy(ReverseEngineeringStrategy delegate) { super(delegate); };
@Override
public String tableToClassName(TableIdentifier table) {
String className = null;
for(int i=0; i!=tableTranslators.length; i++) {
AbstractTable2Class trans = tableTranslators[i];
className = trans.getMap().get(table.getName().toLowerCase());
if( className != null )
break;
}
return className;
}
@Override
public String columnToPropertyName(TableIdentifier table, String column) {
String propertyName = null;
for (int i = 0; i != columnTranslators.length; i++) {
AbstractColumn2Attribute trans = columnTranslators[i];
Map<String, String> tableMap = trans.getMap().get(
table.getName().toLowerCase());
if (tableMap != null) {
propertyName = tableMap.get(column.toLowerCase());
if (propertyName != null)
break;
}
}
return propertyName;
}
// Used to provide only Object types (e.g., Integer instead of int)
@Override
public String columnToHibernateTypeName(TableIdentifier table,
String columnName, int sqlType, int length, int precision,
int scale, boolean nullable, boolean generatedIdentifier) {
String tableName = table.getName().toLowerCase();
for (int i = 0; i < inheritanceTranslators.length; i++) {
if( inheritanceTranslators[i].getEnumTypeForColumn(tableName, columnName.toLowerCase()) != null ) {
return inheritanceTranslators[i].getEnumTypeForColumn(tableName, columnName.toLowerCase());
}
}
return super.columnToHibernateTypeName(table, columnName, sqlType, length,
precision, scale, true, generatedIdentifier);
}
@SuppressWarnings("unchecked")
@Override
public Map tableToMetaAttributes(TableIdentifier tableIdentifier) {
Map map = super.tableToMetaAttributes(tableIdentifier);
if( map == null )
map = new HashMap<String, MetaAttribute>();
// Check if table contains a XMLCLOB column
for (int i = 0; i < inheritanceTranslators.length; i++) {
String tableName = tableIdentifier.getName();
if( inheritanceTranslators[i].hasXmlClobType(tableName) ) {
MetaAttribute mattr = new MetaAttribute(HAS_XML_CLOB_TYPE);
mattr.addValue("true");
map.put(HAS_XML_CLOB_TYPE,mattr);
break;
}
}
// Check if table has a generated ID, necessary to generate the GenericGenerator custom annotation
for (int i = 0; i < inheritanceTranslators.length; i++) {
String tableName = tableIdentifier.getName();
String sequence = inheritanceTranslators[i].getSequenceForTable(tableName);
if( sequence != null ) {
MetaAttribute mattr = new MetaAttribute(ORACLE_SEQUENCE);
mattr.addValue(sequence);
map.put(ORACLE_SEQUENCE,mattr);
break;
}
}
// Check all CHECK constraints for this table
for (int i = 0; i < inheritanceTranslators.length; i++) {
String tableName = tableIdentifier.getName().toLowerCase();
Map<String, String> typesForTable = inheritanceTranslators[i].getEnumTypesForTable(tableName);
if( typesForTable == null || typesForTable.size() == 0)
continue;
else {
MetaAttribute mattr2 = new MetaAttribute(HAS_ENUM_TYPES);
mattr2.addValue("true");
map.put(HAS_ENUM_TYPES, mattr2);
mattr2 = new MetaAttribute(ENUM_TYPES);
Iterator<Map.Entry<String, String>> it = typesForTable.entrySet().iterator();
StringBuilder sb = new StringBuilder();
while(it.hasNext()) {
Map.Entry<String, String> entry = it.next();
sb.append(entry.getKey());
sb.append("|");
sb.append(entry.getValue());
if(it.hasNext())
sb.append(",");
}
mattr2.addValue(sb.toString());
map.put(ENUM_TYPES, mattr2);
}
}
// Check whether table is "Identifiable"
for (int i = 0; i < inheritanceTranslators.length; i++) {
String tableName = tableIdentifier.getName().toLowerCase();
if (inheritanceTranslators[i].isIdentifiable(tableName)) {
MetaAttribute mattr3 = new MetaAttribute(MetaAttributeConstants.IMPLEMENTS);
mattr3.addValue("alma.tmcdb.history.Identifiable");
map.put("implements",mattr3);
}
}
// Check whether table is "Backloggable"
for (int i = 0; i < inheritanceTranslators.length; i++) {
String tableName = tableIdentifier.getName().toLowerCase();
if (inheritanceTranslators[i].isBackloggable(tableName)) {
MetaAttribute mattr4 = new MetaAttribute(MetaAttributeConstants.IMPLEMENTS);
mattr4.addValue("alma.tmcdb.history.Backloggable");
map.put("implements",mattr4);
}
}
// Check if table is superclass or child class
for (int i = 0; i < inheritanceTranslators.length; i++) {
String tableName = tableIdentifier.getName().toLowerCase();
String superClass = inheritanceTranslators[i].getSuperTable(tableName);
if( superClass != null ) {
MetaAttribute mattr = new MetaAttribute(MetaAttributeConstants.EXTENDS);
mattr.addValue(superClass);
map.put("extends",mattr);
return map;
}
else {
MetaAttribute mattr = new MetaAttribute(MetaAttributeConstants.EXTENDS);
mattr.addValue("alma.acs.tmcdb.translator.TmcdbObject");
map.put("extends",mattr);
for(int j=0; j!= inheritanceTranslators.length; j++) {
if( inheritanceTranslators[j].isSuperClass(tableName) ) {
mattr = new MetaAttribute(IS_SUPER_CLASS);
mattr.addValue("true");
map.put(IS_SUPER_CLASS,mattr);
return map;
}
}
}
}
return map;
}
@SuppressWarnings("unchecked")
@Override
public Map columnToMetaAttributes(TableIdentifier identifier, String column) {
Map map = super.columnToMetaAttributes(identifier, column);
if( map == null )
map = new HashMap<String, MetaAttribute>();
String tableName = identifier.getName().toLowerCase();
// Don't generate getter/setters for inheritance-related fields
MetaAttribute mattr = new MetaAttribute(MetaAttributeConstants.GEN_PROPERTY);
for (int i = 0; i < inheritanceTranslators.length; i++) {
List<String> columns = inheritanceTranslators[i].getPkFkCombinationColumns(tableName);
if( columns != null && columns.contains(column.toLowerCase()) ) {
mattr.addValue("false");
map.put("gen-property", mattr);
return map;
}
}
// Make everything protected
mattr.addValue("protected");
map.put("scope-field",mattr);
// Check for special XMLCLOB types, they get a specific annotation generated
for (int i = 0; i < inheritanceTranslators.length; i++) {
if( inheritanceTranslators[i].hasXmlClobType(tableName) ) {
if( inheritanceTranslators[i].isXmlClobType(tableName, column) ) {
MetaAttribute mattr2 = new MetaAttribute(IS_XML_CLOB_TYPE);
mattr2.addValue("true");
map.put(IS_XML_CLOB_TYPE, mattr2);
break;
}
}
}
for (int i = 0; i < inheritanceTranslators.length; i++) {
if( inheritanceTranslators[i].isKeyPiece(tableName, column) ) {
MetaAttribute mattr2 = new MetaAttribute("use-in-equals");
mattr2.addValue("true");
map.put("use-in-equals", mattr2);
break;
}
}
return map;
}
@SuppressWarnings("unchecked")
@Override
public boolean excludeForeignKeyAsCollection(String keyname,
TableIdentifier fromTable, List fromColumns,
TableIdentifier referencedTable, List referencedColumns) {
if( excludeForeignKey(keyname, fromTable, fromColumns, referencedTable, referencedColumns, true) )
return true;
return super.excludeForeignKeyAsCollection(keyname, fromTable, fromColumns,
referencedTable, referencedColumns);
}
@SuppressWarnings("unchecked")
private boolean excludeForeignKey(String keyname,
TableIdentifier fromTable, List fromColumns,
TableIdentifier referencedTable, List referencedColumns,
boolean checkDuplicatedFK) {
for (int i = 0; i < inheritanceTranslators.length; i++) {
String tName = fromTable.getName().toLowerCase();
String superTable = inheritanceTranslators[i].getSuperTable(tName);
String keyName = inheritanceTranslators[i].getKeynameLowercase(tName);
if( superTable != null &&
superTable.toLowerCase().equals(referencedTable.getName().toLowerCase()) &&
keyname.toLowerCase().equals(keyName) ) {
return true;
}
if( checkDuplicatedFK && !inheritanceTranslators[i].generateInverseCollection(tName, ((Column)fromColumns.get(0)).getName() ) )
return true;
}
return false;
}
@SuppressWarnings("unchecked")
@Override
public boolean excludeForeignKeyAsManytoOne(String keyname,
TableIdentifier fromTable, List fromColumns,
TableIdentifier referencedTable, List referencedColumns) {
return excludeForeignKey(keyname, fromTable, fromColumns, referencedTable, referencedColumns, false);
}
@Override
public AssociationInfo foreignKeyToAssociationInfo(
ForeignKey foreignKey) {
DefaulAssociationInfo info = new DefaulAssociationInfo();
String name = foreignKey.getName();
for (int i = 0; i < inheritanceTranslators.length; i++) {
CascadeType cType = inheritanceTranslators[i].getCascadeTypeForForeigKey(name);
if( cType != null ) {
if( cType == CascadeType.NONE) {
info.setCascade("none"); // if not set, it produces an EJB3 "all" cascading
break;
}
else if( cType == CascadeType.AGGREGATION ) {
info.setCascade("save-update, persist, lock");
break;
}
else if( cType == CascadeType.COMPOSITION ) {
info.setCascade("all-delete-orphan");
break;
}
else {
info.setCascade("none"); // fallback
break;
}
}
}
return info;
}
@Override
public AssociationInfo foreignKeyToInverseAssociationInfo(
ForeignKey foreignKey) {
DefaulAssociationInfo info = new DefaulAssociationInfo();
String name = foreignKey.getName();
for (int i = 0; i < inheritanceTranslators.length; i++) {
CascadeType cType = inheritanceTranslators[i].getCascadeTypeForForeigKey(name);
if( cType != null ) {
if( cType == CascadeType.AGGREGATION_INVERSE ) {
info.setCascade("save-update, persist, lock");
break;
}
else if( cType == CascadeType.COMPOSITION_INVERSE ) {
info.setCascade("all-delete-orphan");
break;
}
else {
info.setCascade("none"); // fallback
break;
}
}
}
return info;
}
// @Override
// public boolean excludeColumn(TableIdentifier identifier, String columnName) {
//
// String tableName = identifier.getName().toLowerCase();
// for (int i = 0; i < inheritanceTranslators.length; i++) {
// List<String> columns = inheritanceTranslators[i].getPkFkCombinationColumns(tableName);
// if( columns != null && columns.contains(columnName.toLowerCase()) ) {
// System.out.println("KeyColumns!!!!!!! " + tableName + ":" + columnName);
// return true;
// }
// }
// return super.excludeColumn(identifier, columnName);
// }
}