/*
* 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.lang.reflect.Field;
import javax.persistence.Column;
import javax.persistence.GenerationType;
import org.seasar.extension.jdbc.ColumnMeta;
import org.seasar.extension.jdbc.EntityMeta;
import org.seasar.extension.jdbc.PropertyMeta;
import org.seasar.extension.jdbc.ValueType;
import org.seasar.extension.jdbc.gen.desc.ColumnDesc;
import org.seasar.extension.jdbc.gen.desc.ColumnDescFactory;
import org.seasar.extension.jdbc.gen.dialect.GenDialect;
import org.seasar.extension.jdbc.gen.internal.exception.NullableUniqueNotSupportedRuntimeException;
import org.seasar.extension.jdbc.gen.internal.exception.UnsupportedGenerationTypeRuntimeException;
import org.seasar.extension.jdbc.gen.internal.util.AnnotationUtil;
import org.seasar.extension.jdbc.gen.internal.util.PropertyMetaUtil;
import org.seasar.extension.jdbc.gen.provider.ValueTypeProvider;
import org.seasar.extension.jdbc.gen.sqltype.SqlType;
import org.seasar.framework.util.StringUtil;
/**
* {@link ColumnDescFactory}の実装クラスです。
*
* @author taedium
*/
public class ColumnDescFactoryImpl implements ColumnDescFactory {
/** 方言 */
protected GenDialect dialect;
/** {@link ValueType}の提供者 */
protected ValueTypeProvider valueTypeProvider;
/**
* インスタンスを構築します。
*
* @param dialect
* 方言
* @param valueTypeProvider
* {@link ValueType}の提供者
*/
public ColumnDescFactoryImpl(GenDialect dialect,
ValueTypeProvider valueTypeProvider) {
if (dialect == null) {
throw new NullPointerException("dialect");
}
if (valueTypeProvider == null) {
throw new NullPointerException("valueTypeResolver");
}
this.dialect = dialect;
this.valueTypeProvider = valueTypeProvider;
}
public ColumnDesc getColumnDesc(EntityMeta entityMeta,
PropertyMeta propertyMeta) {
if (propertyMeta.isTransient() || propertyMeta.isRelationship()) {
return null;
}
Column column = getColumn(propertyMeta);
ColumnDesc columnDesc = new ColumnDesc();
doName(entityMeta, propertyMeta, columnDesc, column);
doComment(entityMeta, propertyMeta, columnDesc, column);
doIdentity(entityMeta, propertyMeta, columnDesc, column);
doDefinition(entityMeta, propertyMeta, columnDesc, column);
doNullable(entityMeta, propertyMeta, columnDesc, column);
doUnique(entityMeta, propertyMeta, columnDesc, column);
doSqlType(entityMeta, propertyMeta, columnDesc, column);
return columnDesc;
}
/**
* 名前を処理します。
*
* @param entityMeta
* エンティティメタデータ
* @param propertyMeta
* プロパティメタデータ
* @param columnDesc
* カラム記述
* @param column
* カラム
*/
protected void doName(EntityMeta entityMeta, PropertyMeta propertyMeta,
ColumnDesc columnDesc, Column column) {
ColumnMeta columnMeta = propertyMeta.getColumnMeta();
columnDesc.setName(columnMeta.getName());
}
/**
* コメントを処理します。
*
* @param entityMeta
* エンティティメタデータ
* @param propertyMeta
* プロパティメタデータ
* @param columnDesc
* カラム記述
* @param column
* カラム
*/
protected void doComment(EntityMeta entityMeta, PropertyMeta propertyMeta,
ColumnDesc columnDesc, Column column) {
String comment = PropertyMetaUtil.getComment(propertyMeta);
columnDesc.setComment(comment);
}
/**
* IDENTITYカラムを処理します。
*
* @param entityMeta
* エンティティメタデータ
* @param propertyMeta
* プロパティメタデータ
* @param columnDesc
* カラム記述
* @param column
* カラム
*/
protected void doIdentity(EntityMeta entityMeta, PropertyMeta propertyMeta,
ColumnDesc columnDesc, Column column) {
GenerationType generationType = propertyMeta.getGenerationType();
if (generationType == GenerationType.AUTO) {
generationType = dialect.getDefaultGenerationType();
}
if (generationType == GenerationType.IDENTITY) {
if (!dialect.supportsIdentity()) {
throw new UnsupportedGenerationTypeRuntimeException(
GenerationType.IDENTITY, entityMeta.getName(),
propertyMeta.getName());
}
columnDesc.setIdentity(true);
}
}
/**
* 定義を処理します。
*
* @param entityMeta
* エンティティメタデータ
* @param propertyMeta
* プロパティメタデータ
* @param columnDesc
* カラム記述
* @param column
* カラム
*/
protected void doDefinition(EntityMeta entityMeta,
PropertyMeta propertyMeta, ColumnDesc columnDesc, Column column) {
SqlType type = dialect.getSqlType(valueTypeProvider, propertyMeta);
String dataType = type.getDataType(column.length(), column.precision(),
column.scale(), columnDesc.isIdentity());
String definition;
if (!StringUtil.isEmpty(column.columnDefinition())) {
if (StringUtil.startsWithIgnoreCase(column.columnDefinition(),
"default ")) {
definition = dataType + " " + column.columnDefinition();
} else if (StringUtil.startsWithIgnoreCase(column
.columnDefinition(), "check ")) {
definition = dataType + " " + column.columnDefinition();
} else {
definition = column.columnDefinition();
}
} else {
definition = dataType;
}
columnDesc.setDefinition(definition);
}
/**
* NULL可能かどうかを処理します。
*
* @param entityMeta
* エンティティメタデータ
* @param propertyMeta
* プロパティメタデータ
* @param columnDesc
* カラム記述
* @param column
* カラム
*/
protected void doNullable(EntityMeta entityMeta, PropertyMeta propertyMeta,
ColumnDesc columnDesc, Column column) {
if (propertyMeta.isId()) {
columnDesc.setNullable(false);
} else if (column != AnnotationUtil.getDefaultColumn()) {
columnDesc.setNullable(column.nullable());
} else {
Class<?> clazz = propertyMeta.getField().getType();
columnDesc.setNullable(!clazz.isPrimitive());
}
}
/**
* 一意性を処理します。
*
* @param entityMeta
* エンティティメタデータ
* @param propertyMeta
* プロパティメタデータ
* @param columnDesc
* カラム記述
* @param column
* カラム
*/
protected void doUnique(EntityMeta entityMeta, PropertyMeta propertyMeta,
ColumnDesc columnDesc, Column column) {
columnDesc.setUnique(column.unique());
if (!dialect.supportsNullableUnique()) {
if (columnDesc.isNullable() && columnDesc.isUnique()) {
throw new NullableUniqueNotSupportedRuntimeException(entityMeta
.getName(), propertyMeta.getName());
}
}
}
/**
* SQL型を処理します。
*
* @param entityMeta
* エンティティメタデータ
* @param propertyMeta
* プロパティメタデータ
* @param columnDesc
* カラム記述
* @param column
* カラム
*/
protected void doSqlType(EntityMeta entityMeta, PropertyMeta propertyMeta,
ColumnDesc columnDesc, Column column) {
SqlType sqlType = dialect.getSqlType(valueTypeProvider, propertyMeta);
columnDesc.setSqlType(sqlType);
}
/**
* カラムを返します。
*
* @param propertyMeta
* プロパティメタデータ
* @return カラム
*/
protected Column getColumn(PropertyMeta propertyMeta) {
Field field = propertyMeta.getField();
Column column = field.getAnnotation(Column.class);
return column != null ? column : AnnotationUtil.getDefaultColumn();
}
}