/*
* Copyright 2010 Werner Guttmann
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.castor.cpa.persistence.sql.keygen;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.castor.core.util.Messages;
import org.castor.cpa.persistence.sql.keygen.typehandler.KeyGeneratorTypeHandler;
import org.castor.cpa.persistence.sql.keygen.typehandler.KeyGeneratorTypeHandlerFactory;
import org.castor.jdo.jpa.info.JPATableGeneratorDescriptor;
import org.exolab.castor.jdo.PersistenceException;
import org.exolab.castor.mapping.MappingException;
import org.exolab.castor.persist.spi.PersistenceFactory;
public class TableKeyGenerator extends AbstractBeforeKeyGenerator {
private static final Log LOG = LogFactory.getLog(TableKeyGenerator.class);
public static final String DESCRIPTOR_KEY = "descriptor";
public static final String DEFAULT_TABLE_NAME = "GENERATOR_TABLE";
public static final int DEFAULT_ALLOCATION_SIZE = 50;
public static final int DEFAULT_INITIAL_VALUE = 0;
public static final String DEFAULT_PK_COLUMN_NAME = "ID_NAME";
public static final String DEFAULT_VALUE_COLUMN_NAME = "ID_VALUE";
public static final String DEFAULT_PK_COLUMN_VALUE = "ID_GEN";
private PersistenceFactory factory;
private JPATableGeneratorDescriptor descriptor;
private int sqlType;
/**
* Creates an instance of this key generator.
*
* @param factory The current {@link PersistenceFactory} instance.
* @param params Parameters for the key generator.
* @param sqlType The SQL type of the identity field.
* @throws MappingException
*/
public TableKeyGenerator(PersistenceFactory factory, Properties params,
int sqlType) throws MappingException {
super(factory);
this.factory = factory;
this.sqlType = sqlType;
this.descriptor = (JPATableGeneratorDescriptor) params.get(DESCRIPTOR_KEY);
initializeDescriptor();
assertNumericSqlType(sqlType);
}
private void assertNumericSqlType(int sqlType) throws MappingException {
switch (sqlType) {
case Types.BIGINT:
case Types.SMALLINT:
case Types.INTEGER:
case Types.DECIMAL:
case Types.NUMERIC:
break;
default:
String msg = Messages.format("mapping.keyGenSQLType", getClass()
.getName(), sqlType);
throw new MappingException(msg);
}
}
private void initializeDescriptor() {
if (descriptor == null) {
descriptor = new JPATableGeneratorDescriptor();
}
if ((descriptor.getTable() == null) || ("".equals(descriptor.getTable()))) {
descriptor.setTable(DEFAULT_TABLE_NAME);
}
if (descriptor.getAllocationSize() < 1) {
descriptor.setAllocationSize(DEFAULT_ALLOCATION_SIZE);
}
if (descriptor.getInitialValue() < 0) {
descriptor.setInitialValue(DEFAULT_INITIAL_VALUE);
}
if ((descriptor.getPkColumnName() == null)
|| ("".equals(descriptor.getPkColumnName()))) {
descriptor.setPkColumnName(DEFAULT_PK_COLUMN_NAME);
}
if ((descriptor.getValueColumnName() == null)
|| ("".equals(descriptor.getValueColumnName()))) {
descriptor.setValueColumnName(DEFAULT_VALUE_COLUMN_NAME);
}
if ((descriptor.getPkColumnValue() == null)
|| ("".equals(descriptor.getPkColumnValue()))) {
descriptor.setPkColumnValue(DEFAULT_PK_COLUMN_VALUE);
}
}
public Object generateKey(Connection connection, String tableName,
String primKeyName) throws PersistenceException {
if (LOG.isDebugEnabled()) {
LOG.debug("Generating table-based primary key " + primKeyName
+ " for table " + tableName);
}
String sql = "SELECT " + descriptor.getValueColumnName() + " FROM "
+ descriptor.getTable() + " WHERE "
+ descriptor.getPkColumnName() + "='"
+ descriptor.getPkColumnValue() + "'";
Object key;
try {
PreparedStatement statement = connection.prepareStatement(sql);
ResultSet result = statement.executeQuery();
KeyGeneratorTypeHandler<?> handler = KeyGeneratorTypeHandlerFactory
.getTypeHandler(sqlType, descriptor.getAllocationSize());
key = handler.getNextValue(result);
sql = "UPDATE " + descriptor.getTable() + " SET "
+ descriptor.getValueColumnName() + "="
+ key + " WHERE "
+ descriptor.getPkColumnName() + "='"
+ descriptor.getPkColumnValue() + "'";
statement = connection.prepareStatement(sql);
statement.executeUpdate();
} catch (SQLException e) {
throw new PersistenceException(e.getMessage());
} catch (MappingException e) {
throw new PersistenceException(e.getMessage());
}
return key;
}
public boolean isInSameConnection() {
return true;
}
public PersistenceFactory getFactory() {
return factory;
}
public JPATableGeneratorDescriptor getDescriptor() {
return descriptor;
}
}