/*
* Copyright 2004-2015 the Seasar Foundation and the Others.
*
* 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.seasar.extension.jdbc.gen.internal.desc;
import java.util.regex.Pattern;
import javax.persistence.GenerationType;
import javax.persistence.SequenceGenerator;
import javax.persistence.TableGenerator;
import javax.persistence.Version;
import org.seasar.extension.jdbc.gen.desc.AttributeDesc;
import org.seasar.extension.jdbc.gen.desc.AttributeDescFactory;
import org.seasar.extension.jdbc.gen.dialect.GenDialect;
import org.seasar.extension.jdbc.gen.internal.exception.IdentityNotSupportedRuntimeException;
import org.seasar.extension.jdbc.gen.internal.exception.SequenceNotSupportedRuntimeException;
import org.seasar.extension.jdbc.gen.internal.util.AnnotationUtil;
import org.seasar.extension.jdbc.gen.meta.DbColumnMeta;
import org.seasar.extension.jdbc.gen.meta.DbTableMeta;
import org.seasar.framework.convention.PersistenceConvention;
import org.seasar.framework.util.ClassUtil;
/**
* {@link AttributeDescFactory}の実装クラスです。
*
* @author taedium
*/
public class AttributeDescFactoryImpl implements AttributeDescFactory {
/** 永続化層の命名規約 */
protected PersistenceConvention persistenceConvention;
/** 方言 */
protected GenDialect dialect;
/** バージョンカラム名のパターン */
protected Pattern versionColumnNamePattern;
/** エンティティの識別子の生成方法を示す列挙型 、生成しない場合は{@code null} */
protected GenerationType generationType;
/** エンティティの識別子の初期値 */
protected int initialValue;
/** エンティティの識別子の割り当てサイズ */
protected int allocationSize;
/**
* インスタンスを構築します。
*
* @param persistenceConvention
* 永続化層の命名規約
* @param dialect
* 方言
* @param versionColumnNamePattern
* バージョンカラム名のパターン
* @param generationType
* エンティティの識別子の生成方法を示す列挙型 、生成しない場合は{@code null}
* @param initialValue
* エンティティの識別子の初期値、指定しない場合は{@code null}
* @param allocationSize
* エンティティの識別子の割り当てサイズ、指定しない場合は{@code null}
*/
public AttributeDescFactoryImpl(
PersistenceConvention persistenceConvention, GenDialect dialect,
String versionColumnNamePattern, GenerationType generationType,
Integer initialValue, Integer allocationSize) {
if (persistenceConvention == null) {
throw new NullPointerException("persistenceConvention");
}
if (dialect == null) {
throw new NullPointerException("dialect");
}
if (versionColumnNamePattern == null) {
throw new NullPointerException("versionColumnNamePattern");
}
this.persistenceConvention = persistenceConvention;
this.dialect = dialect;
this.versionColumnNamePattern = Pattern.compile(
versionColumnNamePattern, Pattern.CASE_INSENSITIVE);
this.generationType = generationType == GenerationType.AUTO ? dialect
.getDefaultGenerationType() : generationType;
if (this.generationType == GenerationType.IDENTITY) {
if (!dialect.supportsIdentity()) {
throw new IdentityNotSupportedRuntimeException();
}
} else if (this.generationType == GenerationType.SEQUENCE) {
if (!dialect.supportsSequence()) {
throw new SequenceNotSupportedRuntimeException();
}
SequenceGenerator generator = AnnotationUtil
.getDefaultSequenceGenerator();
this.initialValue = initialValue != null ? initialValue : generator
.initialValue();
this.allocationSize = allocationSize != null ? allocationSize
: generator.allocationSize();
} else if (this.generationType == GenerationType.TABLE) {
TableGenerator generator = AnnotationUtil
.getDefaultTableGenerator();
this.initialValue = initialValue != null ? initialValue : generator
.initialValue();
this.allocationSize = allocationSize != null ? allocationSize
: generator.allocationSize();
}
}
public AttributeDesc getAttributeDesc(DbTableMeta tableMeta,
DbColumnMeta columnMeta) {
AttributeDesc attributeDesc = new AttributeDesc();
doName(tableMeta, columnMeta, attributeDesc);
doId(tableMeta, columnMeta, attributeDesc);
doTransient(tableMeta, columnMeta, attributeDesc);
doColumn(tableMeta, columnMeta, attributeDesc);
doVersion(tableMeta, columnMeta, attributeDesc);
doGenerationType(tableMeta, columnMeta, attributeDesc);
return attributeDesc;
}
/**
* 名前を処理します。
*
* @param tableMeta
* テーブルメタデータ
* @param columnMeta
* カラムメタデータ
* @param attributeDesc
* 属性記述
*/
protected void doName(DbTableMeta tableMeta, DbColumnMeta columnMeta,
AttributeDesc attributeDesc) {
attributeDesc.setName(persistenceConvention
.fromColumnNameToPropertyName(columnMeta.getName()));
}
/**
* 識別子を処理します。
*
* @param tableMeta
* テーブルメタデータ
* @param columnMeta
* カラムメタデータ
* @param attributeDesc
* 属性記述
*/
protected void doId(DbTableMeta tableMeta, DbColumnMeta columnMeta,
AttributeDesc attributeDesc) {
if (columnMeta.isPrimaryKey()) {
attributeDesc.setId(true);
}
}
/**
* 一時的なプロパティを処理します。
*
* @param tableMeta
* テーブルメタデータ
* @param columnMeta
* カラムメタデータ
* @param attributeDesc
* 属性記述
*/
protected void doTransient(DbTableMeta tableMeta, DbColumnMeta columnMeta,
AttributeDesc attributeDesc) {
}
/**
* バージョンを処理します。
*
* @param tableMeta
* テーブルメタデータ
* @param columnMeta
* カラムメタデータ
* @param attributeDesc
* 属性記述
*/
protected void doVersion(DbTableMeta tableMeta, DbColumnMeta columnMeta,
AttributeDesc attributeDesc) {
if (isVersionAnnotatable(attributeDesc.getAttributeClass())) {
if (versionColumnNamePattern.matcher(columnMeta.getName())
.matches()) {
attributeDesc.setVersion(true);
}
}
}
/**
* カラムを処理します。
*
* @param tableMeta
* テーブルメタデータ
* @param columnMeta
* カラムメタデータ
* @param attributeDesc
* 属性記述
*/
protected void doColumn(DbTableMeta tableMeta, DbColumnMeta columnMeta,
AttributeDesc attributeDesc) {
attributeDesc.setColumnName(columnMeta.getName());
attributeDesc.setColumnTypeName(columnMeta.getTypeName());
attributeDesc.setLength(columnMeta.getLength());
attributeDesc.setPrecision(columnMeta.getLength());
attributeDesc.setScale(columnMeta.getScale());
attributeDesc.setNullable(columnMeta.isNullable());
attributeDesc.setUnique(columnMeta.isUnique());
attributeDesc.setComment(columnMeta.getComment());
GenDialect.ColumnType columnType = dialect.getColumnType(
columnMeta.getTypeName(), columnMeta.getSqlType());
if (columnType != null) {
Class<?> clazz = columnType.getAttributeClass(
columnMeta.getLength(), columnMeta.getLength(),
columnMeta.getScale());
attributeDesc.setAttributeClass(clazz);
String defaultValue = attributeDesc.isId() ? null : columnMeta
.getDefaultValue();
String definition = columnType.getColumnDefinition(
columnMeta.getLength(), columnMeta.getLength(),
columnMeta.getScale(), defaultValue);
attributeDesc.setColumnDefinition(definition);
attributeDesc.setLob(columnType.isLob());
attributeDesc.setPrimaryTemporalType(columnType.getTemporalType());
} else {
attributeDesc.setUnsupportedColumnType(true);
attributeDesc.setAttributeClass(String.class);
attributeDesc.setLob(false);
}
}
/**
* {@link GenerationType}を処理します。
*
* @param tableMeta
* テーブルメタデータ
* @param columnMeta
* カラムメタデータ
* @param attributeDesc
* 属性記述
*/
protected void doGenerationType(DbTableMeta tableMeta,
DbColumnMeta columnMeta, AttributeDesc attributeDesc) {
if (columnMeta.isPrimaryKey() && !tableMeta.hasCompositePrimaryKey()) {
Class<?> clazz = ClassUtil.getWrapperClassIfPrimitive(attributeDesc
.getAttributeClass());
if (Number.class.isAssignableFrom(clazz)) {
if (columnMeta.isAutoIncrement()) {
attributeDesc.setGenerationType(GenerationType.IDENTITY);
} else {
attributeDesc.setGenerationType(generationType);
attributeDesc.setInitialValue(initialValue);
attributeDesc.setAllocationSize(allocationSize);
}
}
}
}
/**
* {@link Version}を注釈できるクラスの場合{@code true}
*
* @param clazz
* クラス
* @return {@link Version}を注釈できるクラスの場合{@code true}
*/
protected boolean isVersionAnnotatable(Class<?> clazz) {
Class<?> wrapperClass = ClassUtil.getWrapperClassIfPrimitive(clazz);
return wrapperClass == Integer.class || wrapperClass == Long.class;
}
}