오늘은 어디로 갈까...

5. QueryProvider 본문

ORM 만들기

5. QueryProvider

剛宇 2009. 8. 26. 21:56
 오늘은 QueryProvider에 대해서 알아보도록하겠다.

 QueryProvider는 쿼리를 제공하는 역할을 한다. 우선 제공할 대상인 Query 클래스에 대해서 살펴보자.
 처음 본인이 생각해낸 Query 클래스는 SQL 문장과, 파라메터를 가지는 구조였다. 정적 SQL일 경우에는 이 생각이 틀리지 않았지만, 동적 SQL일 경우는 파라메터에 따라 SQL 문장이 변경되어야만 했다. 그래서 Query 인터페이스를 상속받은 StaticQuery와 DynamicQuery 클래스가 만들어지게 되었다. 그리고 실행이 가능한 Query(SQL 문장이 확정되어진)는 정적 SQL일 경우에만 해당되므로, 실행 가능한 Query를 RunnableQuery 인터페이스로 정의하고, StaticQuery가 구현하도록 하였다. 

즉, 다시 얘기하자면 StaticQuery와 DynamicQuery가 있고, 해당 파라메터에 의해서 DynamicQuery는 StaticQuery를 생성해내게 되는것이다. Query 인터페이스에 정의된 getRunnableQuery(Object parameterObject) 메소드를 통해서이다.
/*
 * Copyright 2002-2009 Team Jaru.
 * 
 * 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 kr.kangwoo.damo.engine.query;

import kr.kangwoo.damo.engine.cache.CacheStrategy;
import kr.kangwoo.damo.engine.executor.interceptor.ExecuteInterceptor;
import kr.kangwoo.damo.engine.executor.interceptor.HandleRowInterceptor;


public interface Query {

	CommandType getCommandType();

	String getDescription();
	
	RunnableQuery getRunnableQuery(Object parameterObject);
	
	ExecuteInterceptor[] getExecuteInterceptors();
	HandleRowInterceptor[] getHandleRowInterceptors();

	Integer getFetchSize();
	Integer getResultSetType();
	Integer getResultSetConcurrency();
	
	// Cache
	String getCacheName();
	CacheStrategy getCacheStrategy();
	
}

/*
 * Copyright 2002-2009 Team Jaru.
 * 
 * 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 kr.kangwoo.damo.engine.query;

import kr.kangwoo.damo.engine.executor.interceptor.ExecuteInterceptor;
import kr.kangwoo.damo.engine.executor.interceptor.HandleRowInterceptor;
import kr.kangwoo.damo.engine.query.parameter.ParameterInfo;

public class StaticQuery extends BaseQuery implements RunnableQuery {

	private String sql;
	private ParameterInfo<?>[] parameterInfos;

	public StaticQuery(CommandType commandType, String sql, ParameterInfo<?>[] parameterInfos) {
		this(commandType, sql, parameterInfos, null, null, null);
	}
	public StaticQuery(CommandType commandType, String sql, ParameterInfo<?>[] parameterInfos, String description) {
		this(commandType, sql, parameterInfos, description, null, null);
	}
	
	public StaticQuery(CommandType commandType, String sql, ParameterInfo<?>[] parameterInfos, String description, ExecuteInterceptor[] executeInterceptors, HandleRowInterceptor[] handleRowInterceptors) {
		super(commandType, description);
		this.sql = sql;
		this.parameterInfos = parameterInfos;
		this.executeInterceptors = executeInterceptors;
		this.handleRowInterceptors = handleRowInterceptors;
	}

	public String getSql() {
		return sql;
	}

	public void setSql(String sql) {
		this.sql = sql;
	}

	public ParameterInfo<?>[] getParameterInfos() {
		return parameterInfos;
	}

	public void setparameterInfos(ParameterInfo<?>[] parameterInfos) {
		this.parameterInfos = parameterInfos;
	}


	public RunnableQuery getRunnableQuery(Object parameterObject) {
		return this;
	}

}


StaticQuery의 getRunnableQuery 메소드는 바로 자기 자신을 반환한다.

 
/*
 * Copyright 2002-2009 Team Jaru.
 * 
 * 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 kr.kangwoo.damo.engine.query;

import java.util.ArrayList;
import java.util.List;

import kr.kangwoo.damo.engine.executor.interceptor.ExecuteInterceptor;
import kr.kangwoo.damo.engine.executor.interceptor.HandleRowInterceptor;
import kr.kangwoo.damo.engine.query.parameter.ParameterInfo;
import kr.kangwoo.damo.engine.query.token.StaticToken;
import kr.kangwoo.damo.engine.query.token.Token;

public class DynamicQuery extends BaseQuery {

	private Token[] tokens;

	public DynamicQuery(CommandType commandType, Token[] tokens) {
		this(commandType, tokens, null, null, null);
	}

	public DynamicQuery(CommandType commandType, Token[] tokens, String description) {
		this(commandType, tokens, description, null, null);
	}

	public DynamicQuery(CommandType commandType, Token[] tokens, String description,
			ExecuteInterceptor[] executeInterceptors,
			HandleRowInterceptor[] handleRowInterceptors) {
		super(commandType, description);
		this.tokens = tokens;
		this.executeInterceptors = executeInterceptors;
		this.handleRowInterceptors = handleRowInterceptors;
	}

	public RunnableQuery getRunnableQuery(Object parameterObject) {
		StringBuilder sql = new StringBuilder();
		List<ParameterInfo<?>> parameterInfoList = new ArrayList<ParameterInfo<?>>();
		for (Token token : tokens) {
			StaticToken staticToken = token.getStaticToken(parameterObject);
			if (staticToken != null) {
				String prepend = token.getPrepend();
				if (prepend != null) {
					sql.append(prepend);
				}
				sql.append(staticToken.getSql());
				if (staticToken.getParameterInfos() != null) {
					for (ParameterInfo<?> pm : staticToken.getParameterInfos()) {
						parameterInfoList.add(pm);
					}
				}
			}
		}
		StaticQuery staticQuery = new StaticQuery(commandType, sql.toString(), ParameterInfo.toArray(parameterInfoList), description);
		staticQuery.setFetchSize(fetchSize);
		staticQuery.setResultSetType(resultSetType);
		staticQuery.setResultSetConcurrency(resultSetConcurrency);
		staticQuery.setExecuteInterceptors(executeInterceptors);
		staticQuery.setHandleRowInterceptors(handleRowInterceptors);
		return staticQuery;
	}
}

 DynmicQuery의 getRunnableQuery 메소드는 해당 파라메터에 맞게 적정한 StaticQuery를 생성해서 반환한다. 


 QueryProvider는 QueryGenerator와 QueryLoader로 이루어져있다. 

 QueryGenerator는 클래스에 정의한 어노테이션을 분석하여 insert/update/delete/select 쿼리를 생성해준다.

 QueryLoader는 지정한 xml을 파일에서 해당하는 쿼리 아이디를 읽어오는 역할을 한다. 기본적으로는 damo.properties에 설정한 xml 파일들을 읽어와서 사용하지만, 사용자 구미에 맞게 얼마든지 변경이 가능하다.
본인 같은 경우에는 java 파일과 xml 파일을 같은 위치에 놓는것을 좋아해서 BlueDao.java, BueDao.xml을 같은 위치에 만들어서 사용하단. BlueDao 클래스는 kr.kangwoo.damo.support.dao.DaoSupportImpl 클래스를 상속받아 해당위치의 동일한 xml을 파일을 읽어오도록 하는것이다.
/*
 * Copyright 2002-2009 Team Jaru.
 * 
 * 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 kr.kangwoo.damo.support.dao;

import java.io.File;
import java.sql.SQLException;

import kr.kangwoo.damo.ExtendedExecutor;
import kr.kangwoo.damo.Messages;
import kr.kangwoo.damo.PersistenceManager;
import kr.kangwoo.damo.engine.batch.BatchCallback;
import kr.kangwoo.damo.engine.batch.BatchResult;
import kr.kangwoo.damo.engine.provider.QueryProvider;
import kr.kangwoo.damo.engine.provider.loader.file.QueryFileLoader;
import kr.kangwoo.damo.engine.provider.loader.file.ReloadableQueryFileLoader;
import kr.kangwoo.damo.engine.provider.loader.file.SimpleQueryFileLoader;
import kr.kangwoo.damo.engine.query.Query;
import kr.kangwoo.damo.engine.query.result.RowHandler;
import kr.kangwoo.util.ClassUtils;
import kr.kangwoo.util.MessageUtils;
import kr.kangwoo.util.io.ClassPathResource;
import kr.kangwoo.util.logging.Logger;
import kr.kangwoo.util.logging.LoggerFactory;


public class DaoSupportImpl extends ExtendedExecutor implements DaoSupport {
	
	protected Logger logger = LoggerFactory.getLogger(getClass());
	protected PersistenceManager persistenceManager;
	
	protected QueryFileLoader queryLoader;
	protected String sqlFilename;

	public DaoSupportImpl() {
		this(PersistenceManager.getPersistenceManager(), 0);
	}
	
	public DaoSupportImpl(PersistenceManager persistenceManager) {
		this(persistenceManager, 0);
	}
	
	public DaoSupportImpl(int reloadSeconds) {
		this(PersistenceManager.getPersistenceManager(), reloadSeconds);
	}
	
	public DaoSupportImpl(PersistenceManager persistenceManager, int reloadSeconds) {
		sqlFilename = ClassUtils.getShortClassName(getClass()) + ".xml"; //$NON-NLS-1$
		ClassPathResource resource = new ClassPathResource(sqlFilename,  getClass());
		if (resource.exists()) {
			logger.debug(MessageUtils.format(Messages.getString("DaoSupportImpl.FILE_FOUND"), sqlFilename)); //$NON-NLS-1$
			try {			
				File file = resource.getFile();
				if (reloadSeconds > 0) {
					queryLoader = new ReloadableQueryFileLoader();	
				} else {
					queryLoader = new SimpleQueryFileLoader();	
				}
				queryLoader.init(new File[] {file});
			} catch(Exception ex) {
				logger.debug(MessageUtils.format(Messages.getString("DaoSupportImpl.PARSE_ERROR"), sqlFilename), ex); //$NON-NLS-1$
			}
		}
		persistenceManager.getQueryProvider();
	}

	public int executeUpdate(Query query, Object parameterObject) throws SQLException {
		return persistenceManager.executeUpdate(query, parameterObject);
	}
	
	public <E> void executeQuery(Query query, Object parameterObject, Class<E> resultClass, RowHandler<E> rowHandler) throws SQLException {
		persistenceManager.executeQuery(query, parameterObject, resultClass, rowHandler);
	}
	
	public <E> void executeQuery(Query query, Object parameterObject, Class<E> resultClass, RowHandler<E> rowHandler, int pageNo, int pageSize) throws SQLException {
		persistenceManager.executeQuery(query, parameterObject, resultClass, rowHandler, pageNo, pageSize);
	}
	
	public <E> E executeCallable(Query query, Object parameterObject, Class<E> resultClass) throws SQLException {
		return persistenceManager.executeCallable(query, parameterObject, resultClass);
	}

	public BatchResult executeBatch(BatchCallback batchCallback)
			throws SQLException {
		return persistenceManager.executeBatch(batchCallback);
	}

	public Query getQuery(String queryId) throws SQLException {
		Query query = null;
		if (queryLoader != null) {
			query = queryLoader.getQuery(queryId);
		}
		return (query != null) ? query : getQueryProvider().getQuery(queryId);
	}

	@Override
	public QueryProvider getQueryProvider() {
		return persistenceManager.getQueryProvider();
	}

}