/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.boot.model.naming;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import org.hibernate.HibernateException;
Author: Steve Ebersole
/**
* @author Steve Ebersole
*/
public class NamingHelper {
Singleton access
/**
* Singleton access
*/
public static final NamingHelper INSTANCE = new NamingHelper();
public static NamingHelper withCharset(String charset) {
return new NamingHelper(charset);
}
private final String charset;
public NamingHelper() {
this(null);
}
private NamingHelper(String charset) {
this.charset = charset;
}
If a foreign-key is not explicitly named, this is called to generate
a unique hash using the table and column names.
/**
* If a foreign-key is not explicitly named, this is called to generate
* a unique hash using the table and column names.
*/
public String generateHashedFkName(
String prefix,
Identifier tableName,
Identifier referencedTableName,
List<Identifier> columnNames) {
final Identifier[] columnNamesArray;
if ( columnNames == null || columnNames.isEmpty() ) {
columnNamesArray = new Identifier[0];
}
else {
columnNamesArray = columnNames.toArray( new Identifier[ columnNames.size() ] );
}
return generateHashedFkName(
prefix,
tableName,
referencedTableName,
columnNamesArray
);
}
If a foreign-key is not explicitly named, this is called to generate
a unique hash using the table and column names.
/**
* If a foreign-key is not explicitly named, this is called to generate
* a unique hash using the table and column names.
*/
public String generateHashedFkName(
String prefix,
Identifier tableName,
Identifier referencedTableName,
Identifier... columnNames) {
// Use a concatenation that guarantees uniqueness, even if identical names
// exist between all table and column identifiers.
StringBuilder sb = new StringBuilder()
.append( "table`" ).append( tableName ).append( "`" )
.append( "references`" ).append( referencedTableName ).append( "`" );
// Ensure a consistent ordering of columns, regardless of the order
// they were bound.
// Clone the list, as sometimes a set of order-dependent Column
// bindings are given.
Identifier[] alphabeticalColumns = columnNames.clone();
Arrays.sort(
alphabeticalColumns,
new Comparator<Identifier>() {
@Override
public int compare(Identifier o1, Identifier o2) {
return o1.getCanonicalName().compareTo( o2.getCanonicalName() );
}
}
);
for ( Identifier columnName : alphabeticalColumns ) {
sb.append( "column`" ).append( columnName ).append( "`" );
}
return prefix + hashedName( sb.toString() );
}
If a constraint is not explicitly named, this is called to generate
a unique hash using the table and column names.
Returns: String The generated name
/**
* If a constraint is not explicitly named, this is called to generate
* a unique hash using the table and column names.
*
* @return String The generated name
*/
public String generateHashedConstraintName(String prefix, Identifier tableName, Identifier... columnNames ) {
// Use a concatenation that guarantees uniqueness, even if identical names
// exist between all table and column identifiers.
StringBuilder sb = new StringBuilder( "table`" + tableName + "`" );
// Ensure a consistent ordering of columns, regardless of the order
// they were bound.
// Clone the list, as sometimes a set of order-dependent Column
// bindings are given.
Identifier[] alphabeticalColumns = columnNames.clone();
Arrays.sort(
alphabeticalColumns,
new Comparator<Identifier>() {
@Override
public int compare(Identifier o1, Identifier o2) {
return o1.getCanonicalName().compareTo( o2.getCanonicalName() );
}
}
);
for ( Identifier columnName : alphabeticalColumns ) {
sb.append( "column`" ).append( columnName ).append( "`" );
}
return prefix + hashedName( sb.toString() );
}
If a constraint is not explicitly named, this is called to generate
a unique hash using the table and column names.
Returns: String The generated name
/**
* If a constraint is not explicitly named, this is called to generate
* a unique hash using the table and column names.
*
* @return String The generated name
*/
public String generateHashedConstraintName(String prefix, Identifier tableName, List<Identifier> columnNames) {
Identifier[] columnNamesArray = new Identifier[columnNames.size()];
for ( int i = 0; i < columnNames.size(); i++ ) {
columnNamesArray[i] = columnNames.get( i );
}
return generateHashedConstraintName( prefix, tableName, columnNamesArray );
}
Hash a constraint name using MD5. Convert the MD5 digest to base 35
(full alphanumeric), guaranteeing
that the length of the name will always be smaller than the 30
character identifier restriction enforced by a few dialects.
Params: - s – The name to be hashed.
Returns: String The hashed name.
/**
* Hash a constraint name using MD5. Convert the MD5 digest to base 35
* (full alphanumeric), guaranteeing
* that the length of the name will always be smaller than the 30
* character identifier restriction enforced by a few dialects.
*
* @param s The name to be hashed.
*
* @return String The hashed name.
*/
public String hashedName(String s) {
try {
MessageDigest md = MessageDigest.getInstance( "MD5" );
md.reset();
md.update( charset != null ? s.getBytes( charset ) : s.getBytes() );
byte[] digest = md.digest();
BigInteger bigInt = new BigInteger( 1, digest );
// By converting to base 35 (full alphanumeric), we guarantee
// that the length of the name will always be smaller than the 30
// character identifier restriction enforced by a few dialects.
return bigInt.toString( 35 );
}
catch ( NoSuchAlgorithmException|UnsupportedEncodingException e ) {
throw new HibernateException( "Unable to generate a hashed name!", e );
}
}
}