/*
* Copyright 2014 mango.jfaster.org
*
* The Mango Project licenses this file to you 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.jfaster.mango.operator;
import org.jfaster.mango.annotation.Mapper;
import org.jfaster.mango.annotation.Result;
import org.jfaster.mango.annotation.Results;
import org.jfaster.mango.binding.BoundSql;
import org.jfaster.mango.binding.InvocationContext;
import org.jfaster.mango.descriptor.MethodDescriptor;
import org.jfaster.mango.descriptor.ReturnDescriptor;
import org.jfaster.mango.jdbc.*;
import org.jfaster.mango.mapper.BeanPropertyRowMapper;
import org.jfaster.mango.mapper.RowMapper;
import org.jfaster.mango.mapper.SingleColumnRowMapper;
import org.jfaster.mango.parser.ASTRootNode;
import org.jfaster.mango.parser.EmptyObjectException;
import org.jfaster.mango.stat.OneExecuteStat;
import org.jfaster.mango.type.TypeHandlerRegistry;
import org.jfaster.mango.util.reflect.Reflection;
import javax.sql.DataSource;
import java.lang.reflect.Array;
import java.util.HashMap;
import java.util.Map;
/**
* @author ash
*/
public class QueryOperator extends AbstractOperator {
protected RowMapper<?> rowMapper;
protected ReturnDescriptor returnDescriptor;
protected ListSupplier listSupplier;
protected SetSupplier setSupplier;
public QueryOperator(ASTRootNode rootNode, MethodDescriptor md, Config config) {
super(rootNode, md, config);
init(md);
}
private void init(MethodDescriptor md) {
returnDescriptor = md.getReturnDescriptor();
rowMapper = getRowMapper(returnDescriptor.getMappedClass(), returnDescriptor);
if (returnDescriptor.isCollection()
|| returnDescriptor.isList()
|| returnDescriptor.isLinkedList()) {
listSupplier = new LinkedListSuppliter();
} else if (returnDescriptor.isArrayList()) {
listSupplier = new ArrayListSuppliter();
} else if (returnDescriptor.isSetAssignable()) {
setSupplier = new HashSetSupplier();
}
}
@Override
public Object execute(Object[] values, OneExecuteStat stat) {
InvocationContext context = invocationContextFactory.newInvocationContext(values);
return execute(context, stat);
}
protected Object execute(InvocationContext context, OneExecuteStat stat) {
context.setGlobalTable(tableGenerator.getTable(context));
try {
rootNode.render(context);
} catch (EmptyObjectException e) {
if (config.isCompatibleWithEmptyList()) {
return EmptyObject();
} else {
throw e;
}
}
BoundSql boundSql = context.getBoundSql();
DataSource ds = dataSourceGenerator.getDataSource(context, daoClass);
invocationInterceptorChain.intercept(boundSql, context, ds); // 拦截器
return executeFromDb(ds, boundSql, stat);
}
private Object executeFromDb(final DataSource ds, final BoundSql boundSql, OneExecuteStat stat) {
Object r;
boolean success = false;
long now = System.nanoTime();
try {
r = new QueryVisitor() {
@Override
Object visitForList() {
return jdbcOperations.queryForList(ds, boundSql, listSupplier, rowMapper);
}
@Override
Object visitForSet() {
return jdbcOperations.queryForSet(ds, boundSql, setSupplier, rowMapper);
}
@Override
Object visitForArray() {
return jdbcOperations.queryForArray(ds, boundSql, rowMapper);
}
@Override
Object visitForObject() {
return jdbcOperations.queryForObject(ds, boundSql, rowMapper);
}
}.visit();
success = true;
} finally {
long cost = System.nanoTime() - now;
if (success) {
stat.recordDatabaseExecuteSuccess(cost);
} else {
stat.recordDatabaseExecuteException(cost);
}
}
return r;
}
private <T> RowMapper<?> getRowMapper(Class<T> clazz, ReturnDescriptor rd) {
Mapper mapperAnno = rd.getAnnotation(Mapper.class);
if (mapperAnno != null) { // 自定义mapper
return Reflection.instantiateClass(mapperAnno.value());
}
if (TypeHandlerRegistry.hasTypeHandler(clazz)) { // 单列mapper
return new SingleColumnRowMapper<T>(clazz);
}
// 类属性mapper
Results resultsAnoo = rd.getAnnotation(Results.class);
Map<String, String> ptc = new HashMap<String, String>();
if (resultsAnoo != null) {
Result[] resultAnnos = resultsAnoo.value();
if (resultAnnos != null) {
for (Result resultAnno : resultAnnos) {
ptc.put(resultAnno.property().trim(),
resultAnno.column().trim());
}
}
}
return new BeanPropertyRowMapper<T>(clazz, ptc, config.isCheckColumn());
}
protected Object EmptyObject() {
return new QueryVisitor() {
@Override
Object visitForList() {
return listSupplier.get(rowMapper.getMappedClass());
}
@Override
Object visitForSet() {
return setSupplier.get(rowMapper.getMappedClass());
}
@Override
Object visitForArray() {
return Array.newInstance(rowMapper.getMappedClass(), 0);
}
@Override
Object visitForObject() {
return null;
}
}.visit();
}
abstract class QueryVisitor {
public Object visit() {
Object r;
if (returnDescriptor.isCollection()
|| returnDescriptor.isListAssignable()) {
r = visitForList();
} else if (returnDescriptor.isSetAssignable()) {
r = visitForSet();
} else if (returnDescriptor.isArray()) {
r = visitForArray();
} else {
r = visitForObject();
}
return r;
}
abstract Object visitForList();
abstract Object visitForSet();
abstract Object visitForArray();
abstract Object visitForObject();
}
}