package com.cabletech.common.util;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.commons.lang.StringUtils;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.exception.JDBCExceptionHelper;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.id.Configurable;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.mapping.Table;
import org.hibernate.type.Type;
import org.hibernate.util.PropertiesHelper;
/**
* 用法:
* <id name="id" type="java.lang.String" column="id">
<generator class="com.cabletech.commons.hb.StrSequenceGenerator">
<param name="sequence">SEQ_WORKSHEET_ID</param>
<param name="length">10</param>
</generator>
</id>
* @author YuLeyuan
*
*/
public class StrSequenceGenerator implements PersistentIdentifierGenerator,
Configurable {
/**
* 日志输出.
*/
private final Logger log = LoggerFactory
.getLogger(StrSequenceGenerator.class);
/**
* 缺省的Sequence的名.
*/
public static final String SEQUENCE = "sequence";
/**
* 表示生成的Sequence的长度的Key名.
*/
private static final String LENGTH_KEY = "length";
/**
* 表示生成的Sequence的前缀的Key名.
*/
private static final String PREFIX_KEY = "prefix";
/**
* 默认的Sequence的长度的常量值.
*/
private static final int DEFAULT_SEQUENCE_LENGTH = 12;
/**
* 默认生成的sequence字符串的长度.
*/
private int length = DEFAULT_SEQUENCE_LENGTH;
/**
* 前缀.
*/
private String prefix = null;
/**
* The parameters parameter, appended to the create sequence DDL. For
* example (Oracle):
* <tt>INCREMENT BY 1 START WITH 1 MAXVALUE 100 NOCACHE</tt>.
*/
public static final String PARAMETERS = "parameters";
private String sequenceName;
private String parameters;
private String nextValueSql;
private String createSequenceSql;
private String checkExistSql;
private boolean checked = false;
@Override
public void configure(Type type, Properties params, Dialect dialect)
throws MappingException {
length = PropertiesHelper.getInt(LENGTH_KEY, params,
DEFAULT_SEQUENCE_LENGTH);
prefix = PropertiesHelper.getString(PREFIX_KEY, params, null);
ObjectNameNormalizer normalizer = (ObjectNameNormalizer) params
.get(IDENTIFIER_NORMALIZER);
sequenceName = normalizer.normalizeIdentifierQuoting(PropertiesHelper
.getString(SEQUENCE, params, "hibernate_sequence"));
parameters = params.getProperty(PARAMETERS);
if (sequenceName.indexOf('.') < 0) {
final String schemaName = normalizer
.normalizeIdentifierQuoting(params.getProperty(SCHEMA));
final String catalogName = normalizer
.normalizeIdentifierQuoting(params.getProperty(CATALOG));
sequenceName = Table.qualify(dialect.quote(catalogName),
dialect.quote(schemaName), dialect.quote(sequenceName));
}
// this.identifierType = type;
nextValueSql = getSequenceNextValString();
createSequenceSql = sqlCreateStrings(dialect)[0];
checkExistSql = getCheckExistString();
}
/**
* 获取下一个新序列号
* @return
*/
private String getSequenceNextValString() {
String zeros = StringUtils.repeat("0", length);
if (StringUtils.isEmpty(prefix)) {
return String.format(
"select to_char(%s.nextval,'FM%s') as value from dual",
sequenceName, zeros);
} else {
return String
.format("select '%s'||to_char(%s.nextval,'FM%s') as value from dual",
prefix, sequenceName, zeros);
}
}
private String getCheckExistString() {
return String.format(
"SELECT count(*) FROM user_sequences where sequence_name='%s'",
sequenceName.toUpperCase());
}
@Override
public Serializable generate(SessionImplementor session, Object obj) {
// EntityEntry entry=session.getPersistenceContext().getEntry(obj);
if (!checked) {
if (!isExist(session)) {
createSequence(session);
}
checked = true;
}
return makeNextValue(session);
}
/**
* sequence是否存在
* @param session
* @return
*/
protected boolean isExist(SessionImplementor session) {
try {
PreparedStatement st = session.getBatcher().prepareSelectStatement(
checkExistSql);
try {
ResultSet rs = st.executeQuery();
try {
rs.next();
int flag = rs.getInt(1);
return flag > 0;
} finally {
rs.close();
}
} finally {
session.getBatcher().closeStatement(st);
}
} catch (SQLException sqle) {
throw JDBCExceptionHelper.convert(session.getFactory()
.getSQLExceptionConverter(), sqle,
"could not get next sequence value", checkExistSql);
}
}
/**
* 创建序列号
* @param session
*/
protected void createSequence(SessionImplementor session) {
log.info("Sequence[{}]不存在,自动创建", sequenceName);
try {
PreparedStatement st = session.getBatcher().prepareSelectStatement(
createSequenceSql);
try {
st.executeUpdate();
} finally {
session.getBatcher().closeStatement(st);
}
} catch (SQLException sqle) {
throw JDBCExceptionHelper.convert(session.getFactory()
.getSQLExceptionConverter(), sqle,
"could not get next sequence value", createSequenceSql);
}
}
/**
* 获取下一个序列号
* @param session
* @return
*/
protected String makeNextValue(SessionImplementor session) {
try {
PreparedStatement st = session.getBatcher().prepareSelectStatement(
nextValueSql);
try {
ResultSet rs = st.executeQuery();
try {
rs.next();
String result = rs.getString(1);
if (log.isDebugEnabled()) {
log.debug("Sequence identifier generated: " + result);
}
return result;
} finally {
rs.close();
}
} finally {
session.getBatcher().closeStatement(st);
}
} catch (SQLException sqle) {
throw JDBCExceptionHelper.convert(session.getFactory()
.getSQLExceptionConverter(), sqle,
"could not get next sequence value", nextValueSql);
}
}
/**
* 产生生成sequence的ddl语句
* @param dialect
*/
public String[] sqlCreateStrings(Dialect dialect) throws HibernateException {
String[] ddl = dialect.getCreateSequenceStrings(sequenceName, 1, 1);
if (parameters != null) {
ddl[ddl.length - 1] += ' ' + parameters;
}
return ddl;
}
/**
* 产生删除sequence的ddl语句
* @param dialect
*/
public String[] sqlDropStrings(Dialect dialect) throws HibernateException {
return dialect.getDropSequenceStrings(sequenceName);
}
@Override
public Object generatorKey() {
return sequenceName;
}
public String getSequenceName() {
return sequenceName;
}
}