package org.jblooming.persistence.hibernate.oracle;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.exception.JDBCExceptionHelper;
import org.hibernate.id.Configurable;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.id.IdentifierGeneratorHelper;
import org.hibernate.id.factory.IdentifierGeneratorFactory;
import org.hibernate.id.factory.DefaultIdentifierGeneratorFactory;
import org.hibernate.mapping.Table;
import org.hibernate.type.Type;
import org.hibernate.util.PropertiesHelper;
import org.jblooming.utilities.ReflectionUtilities;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import static java.util.Arrays.asList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
/**
* @author Pietro Polsinelli ppolsinelli@open-lab.com
* @author Roberto Bicchierai rbicchierai@open-lab.com
*/
public class PlatformSequenceGenerator implements PersistentIdentifierGenerator, Configurable {
/**
* The sequence parameter
*/
public static final String SEQUENCE = "sequence";
/**
* 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 Type identifierType;
private String sql;
private static Collection<Sequence> sequences;
private static final Log log = LogFactory.getLog(PlatformSequenceGenerator.class);
public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
this.sequenceName = PropertiesHelper.getString(SEQUENCE, params, "hibernate_sequence");
this.parameters = params.getProperty(PARAMETERS);
String schemaName = params.getProperty(SCHEMA);
String catalogName = params.getProperty(CATALOG);
if (sequenceName.indexOf(".") < 0) {
sequenceName = Table.qualify(catalogName, schemaName, sequenceName);
}
this.identifierType = type;
sql = dialect.getSequenceNextValString(sequenceName);
}
public static void inject(Collection<Sequence> sequences, Dialect dialect) {
PlatformSequenceGenerator.sequences = sequences;
for (Sequence sequence : sequences) {
sequence.sql = dialect.getSequenceNextValString(sequence.name);
}
}
public Serializable generate(SessionImplementor session, Object obj) throws HibernateException {
PreparedStatement st = null;
try {
boolean found = false;
if (sequences != null)
for (Sequence sequence : sequences) {
if (ReflectionUtilities.instanceOfPersistent(obj, sequence.superClass)) {
st = session.getBatcher().prepareSelectStatement(sequence.sql);
found = true;
break;
}
}
if (!found)
st = session.getBatcher().prepareSelectStatement(sql);
try {
ResultSet rs = st.executeQuery();
final Serializable result;
try {
rs.next();
result = IdentifierGeneratorHelper.get(rs, identifierType);
}
finally {
rs.close();
}
if (log.isDebugEnabled())
log.debug("Sequence identifier generated: " + result);
return result;
}
finally {
session.getBatcher().closeStatement(st);
}
}
catch (SQLException sqle) {
throw JDBCExceptionHelper.convert(
session.getFactory().getSQLExceptionConverter(),
sqle,
"could not get next sequence value",
sql
);
}
}
public String[] sqlCreateStrings(Dialect dialect) throws HibernateException {
String[] mainDdl = dialect.getCreateSequenceStrings(sequenceName);
if (parameters != null) mainDdl[mainDdl.length - 1] += ' ' + parameters;
List<String> ddlSimple = new ArrayList(asList(mainDdl));
if (sequences != null)
for (Sequence sequence : sequences) {
String[] tmpDdl = dialect.getCreateSequenceStrings(sequence.name);
if (sequence.parameters != null) tmpDdl[tmpDdl.length - 1] += ' ' + sequence.parameters;
List<String> tmp = asList(tmpDdl);
ddlSimple.addAll(tmp);
}
int i = 0;
String[] ddl = new String[ddlSimple.size()];
for (String sn : ddlSimple) {
ddl[i] = sn;
i++;
}
return ddl;
}
public String[] sqlDropStrings(Dialect dialect) throws HibernateException {
return dialect.getDropSequenceStrings(sequenceName);
}
public Object generatorKey() {
return sequenceName;
}
}