/*
* Copyright 2012 The Solmix Project
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.gnu.org/licenses/
* or see the FSF site: http://www.fsf.org.
*/
package org.solmix.fmk.datasource;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Map;
import javax.xml.namespace.QName;
import org.solmix.api.datasource.DataSource;
import org.solmix.api.datasource.DataSourceData;
import org.solmix.api.datasource.DataSourceGenerator;
import org.solmix.api.exception.SlxException;
import org.solmix.api.jaxb.Efield;
import org.solmix.api.jaxb.TdataSource;
import org.solmix.api.jaxb.Tfield;
import org.solmix.api.jaxb.Tfields;
import org.solmix.api.jaxb.Tvalue;
import org.solmix.api.jaxb.TvalueMap;
import org.solmix.api.types.Texception;
import org.solmix.api.types.Tmodule;
import org.solmix.commons.util.ClassLoaderUtils;
import org.solmix.commons.util.DataUtils;
import org.solmix.fmk.SlxContext;
import org.solmix.fmk.internal.DatasourceCM;
/**
*
* @author Administrator
* @version 110035 2011-6-22
*/
public class BasicGenerator implements DataSourceGenerator
{
private final DataSource datasource;
/**
* @param sc
*/
public BasicGenerator(DataSource datasource)
{
this.datasource = datasource;
}
protected DataSource getDataSource() {
return this.datasource;
}
@Override
public DataSource generateDataSource(DataSourceData context) throws SlxException {
DataSource ds = datasource.instance(context);
return ds;
}
/**
* {@inheritDoc}
*
* @see org.solmix.api.datasource.DataSourceGenerator#deriveSchema(org.solmix.api.datasource.DataSourceData)
*/
@Override
public DataSource deriveSchema(DataSourceData context) throws SlxException {
TdataSource pds = context.getTdataSource();
String parentID = pds.getID();
String schemaClass = context.getTdataSource().getSchemaClass();
TdataSource data = null;
Class<?> clz = null;
// first form schemaClass.
if (schemaClass != null) {
clz = loadClass(schemaClass);
data = deriveFromSchemaClass(parentID, clz);
} else {// no found schema used bean instead of it.
String bean = context.getTdataSource().getBean();
if (bean != null) {
clz = loadClass(bean);
data = deriveFromJavaBean(parentID, clz);
}
}
if (data != null) {
DataSourceData schemaContext = new DataSourceData(data);
schemaContext.setAttribute(SCHEMA_CLASS, clz);
return generateDataSource(schemaContext);
}
DataSourceData schemaContext = deriveFromType();
return schemaContext == null ? null : generateDataSource(schemaContext);
}
protected TdataSource deriveFromSchemaClass(String parentID, Class<?> clz) throws SlxException {
return deriveFromField(parentID,clz);
}
protected TdataSource deriveFromJavaBean(String parentID, Class<?> clz) throws SlxException {
return deriveFromProperty(parentID,clz);
}
protected TdataSource deriveFromField(String parentID, Class<?> clz) throws SlxException {
TdataSource data = new TdataSource();
data.setID(deriveID(clz, parentID));
/** generatedBy */
data.getOtherAttributes().put(new QName("generatedBy"), DatasourceCM.FRAMEWORK_VERSION);
data.getOtherAttributes().put(new QName("schemaClassName"), clz.getName());
Field[] declaredFields = clz.getDeclaredFields();
if (declaredFields == null)
return null;
Tfields fields = new Tfields();
data.setFields(fields);
for (Field field : declaredFields) {
Tfield tf = deriveTfield(field);
if (tf != null)
fields.getField().add(tf);
}
return data;
}
protected Tfield deriveTfield(Field field) {
String name = field.getName();
int modifier = field.getModifiers();
if (Modifier.isStatic(modifier))
return null;
Class<?> type = field.getType();
Efield fieldType = adapteType(type);
TvalueMap valueMap = null;
if (fieldType == Efield.ENUM) {
Object constants[] = type.getEnumConstants();
valueMap = new TvalueMap();
for (Object i : constants) {
String proName = i.toString();
String value = DataUtils.deriveTileFromName(proName);
Tvalue tv = new Tvalue();
tv.setId(proName);
tv.setName(value);
valueMap.getValue().add(tv);
}
}
/** field type */
Tfield buildField = new Tfield();
buildField.setName(name);
buildField.setType(fieldType);
buildField.setDerived(true);
if (valueMap != null)
buildField.setValueMap(valueMap);
return buildField;
}
protected Tfield deriveTfield(PropertyDescriptor propDesc) {
String name = propDesc.getName();
Class<?> type = propDesc.getPropertyType();
Efield fieldType = adapteType(type);
TvalueMap valueMap = null;
if (fieldType == Efield.ENUM) {
Object constants[] = type.getEnumConstants();
valueMap = new TvalueMap();
for (Object i : constants) {
String proName = i.toString();
String value = DataUtils.deriveTileFromName(proName);
Tvalue tv = new Tvalue();
tv.setId(proName);
tv.setName(value);
valueMap.getValue().add(tv);
}
}
Tfield buildField = new Tfield();
buildField.setName(name);
buildField.setType(fieldType);
buildField.setDerived(true);
if (valueMap != null)
buildField.setValueMap(valueMap);
return buildField;
}
public static Efield adapteType(Class<?> type) {
Efield fieldType = null;
String typeName = type.getName();
if (type.isEnum()) {
fieldType = Efield.ENUM;
} else if (String.class.isAssignableFrom(type) || Character.class.isAssignableFrom(type) || "char".equals(typeName))
fieldType = Efield.TEXT;
else if (Boolean.class.isAssignableFrom(type) || "boolean".equals(typeName))
fieldType = Efield.BOOLEAN;
else if (java.sql.Time.class.isAssignableFrom(type))
fieldType = Efield.TIME;
else if (java.sql.Timestamp.class.isAssignableFrom(type))
fieldType = Efield.DATETIME;
else if (java.util.Date.class.isAssignableFrom(type))
fieldType = Efield.DATE;
else if (java.lang.Byte.class.isAssignableFrom(type) || "byte".equals(typeName) || java.lang.Short.class.isAssignableFrom(type)
|| "short".equals(typeName) || java.lang.Integer.class.isAssignableFrom(type) || "int".equals(typeName)
|| java.lang.Long.class.isAssignableFrom(type) || "long".equals(typeName) || java.math.BigInteger.class.isAssignableFrom(type))
fieldType = Efield.INTEGER;
else if (java.lang.Float.class.isAssignableFrom(type) || "float".equals(typeName) || java.lang.Double.class.isAssignableFrom(type)
|| "double".equals(typeName) || java.lang.Number.class.isAssignableFrom(type) || java.math.BigDecimal.class.isAssignableFrom(type))
fieldType = Efield.FLOAT;
else {
fieldType = Efield.UNKNOWN;
}
return fieldType;
}
protected String deriveID(Class<?> clz, String parentID) {
String ID = clz.getName().substring(clz.getName().lastIndexOf(".") + 1);
return new StringBuilder().append(ID).append(DERIVE_KEY).append(parentID).toString();
}
protected TdataSource deriveFromProperty(String parentID, Class<?> clz) throws SlxException {
TdataSource data = new TdataSource();
data.setID(deriveID(clz, parentID));
String core_version = DatasourceCM.FRAMEWORK_VERSION;
/** generatedBy */
data.getOtherAttributes().put(new QName("generatedBy"), core_version);
data.getOtherAttributes().put(new QName("beanClassName"), clz.getName());
try {
Map<String, PropertyDescriptor> propDes = DataUtils.getPropertyDescriptors(clz);
if (propDes.isEmpty())
return null;
Tfields fields = new Tfields();
data.setFields(fields);
for (String key : propDes.keySet()) {
PropertyDescriptor desc = propDes.get(key);
Tfield tf = deriveTfield(desc);
if (tf != null)
fields.getField().add(tf);
}
return data;
} catch (Exception e) {
throw new SlxException(Tmodule.DATASOURCE, Texception.DS_GENERATE_DS_ERROR, e);
}
}
/**
* derived the Tdatasource by custom server type configurarion.such as sql with table ,and jpa with entity bean .
*
* @param clz
* @return
* @throws SlxException
*/
protected DataSourceData deriveFromType() throws SlxException {
return null;
}
public static Class<?> loadClass(String className) throws SlxException {
Class<?> clz = null;
try {
clz = ClassLoaderUtils.loadClass(className,BasicGenerator.class);
if (clz == null) {
ClassLoader loader = SlxContext.getThreadSystemContext().getExtension(ClassLoader.class);
clz = loader.loadClass(className);
}
} catch (ClassNotFoundException e) {
throw new SlxException(Tmodule.DATASOURCE, Texception.NO_FOUND, e);
}
return clz;
}
}