/*
String[] * Copyright 2007 The Fornax Project Team, including the original
* author or authors.
*
* 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.sculptor.framework.accessimpl.jpa;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceException;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
/**
* <p>
* Implementation of Access command FindByQueryAccess.
* </p>
* <p>
* Command design pattern.
* </p>
*/
public abstract class JpaQueryAccessBase<T,R>
extends JpaAccessBase<T> {
private List<R> listResult = null;
private R singleResult = null;
private Class<T> type;
private Class<R> resultType = null;
private Long resultCount = null;
private Map<String, Object> hints = new HashMap<String, Object>();
private Map<String, Object> parameters = new HashMap<String, Object>();
private QueryConfig config = new QueryConfig.Default();
public JpaQueryAccessBase () {
super();
}
@SuppressWarnings("unchecked")
public JpaQueryAccessBase (Class<T> type) {
super();
setPersistentClass(type);
setType(type);
setResultType((Class<R>)type);
}
public JpaQueryAccessBase (Class<T> type, Class<R> resultType) {
super();
setPersistentClass(type);
setType(type);
setResultType(resultType);
}
protected int getFirstResult() {
return config.getFirstResult();
}
public void setFirstResult(int firstResult) {
config.setFirstResult(firstResult);
}
protected int getMaxResult() {
return config.getMaxResults();
}
public void setMaxResult(int maxResult) {
config.setMaxResults(maxResult);
}
protected QueryConfig getConfig() {
return config;
}
protected Map<String, Object> getParameters() {
return parameters;
}
public void setParameters(Map<String, Object> parameters) {
this.parameters = parameters;
}
public void addParameter(String name, Object value) {
parameters.put(name, value);
}
protected boolean isUseSingleResult() {
return getConfig().isSingleResult();
}
public void setUseSingleResult(boolean useSingleResult) {
getConfig().setSingleResult(useSingleResult);
}
public Class<R> getResultType() {
return resultType;
}
public void setResultType(Class<R> resultType) {
this.resultType = resultType;
}
public Class<T> getType() {
return type;
}
public void setType(Class<T> type) {
this.type = type;
}
public R getSingleResult() {
if (singleResult != null) {
return singleResult;
}
if (listResult != null && !listResult.isEmpty()) {
return listResult.get(0);
}
return null;
}
protected void setSingleResult(R singleResult) {
this.singleResult = singleResult;
}
public List<R> getListResult() {
return this.listResult;
}
protected void setListResult(List<R> listResult) {
this.listResult = listResult;
}
public Long getResultCount() {
return resultCount;
}
protected void setResultCount(Long resultCount) {
this.resultCount = resultCount;
}
public void setHint(String hint, Object value) {
hints.put(hint, value);
}
@SuppressWarnings("unchecked")
@Override
final public void performExecute() throws PersistenceException {
init();
validate();
prepareConfig(config);
prepareQuery(config);
prepareOrderBy(config);
// there is no support for Tuple in JPQL, need an untyped query for jpql queries with more than one result expression
// TODO: refactoring
if (resultType.isArray()) {
Query query = prepareUntypedQuery(config);
prepareParameters(query, getParameters(), config);
preparePagination(query, config);
prepareHints(query, config);
if (config.isSingleResult()) {
try {
singleResult = (R) query.getSingleResult();
}
catch (NoResultException e) {
singleResult = null;
}
prepareSingleResult(singleResult);
}
else {
listResult = (List<R>) query.getResultList();
}
}
else {
TypedQuery<R> typedQuery = prepareTypedQuery(config);
prepareParameters(typedQuery, getParameters(), config);
preparePagination(typedQuery, config);
prepareHints(typedQuery, config);
if (config.isSingleResult()) {
try {
singleResult = typedQuery.getSingleResult();
}
catch (NoResultException e) {
singleResult = null;
}
prepareSingleResult(singleResult);
}
else {
listResult = typedQuery.getResultList();
prepareResult(listResult);
}
}
if (config.isResultCountNeeded()) {
// TypedQuery<Long> typedResultCountQuery = prepareResultCount(config);
prepareResultCount(config);
// TODO: run executeResultCount automatically, create handling for that
// executeResultCount();
}
}
protected void init() { }
protected void validate() { }
protected void prepareConfig(QueryConfig config) { }
protected void prepareQuery(QueryConfig config) { }
protected void prepareOrderBy(QueryConfig config) { }
abstract protected TypedQuery<R> prepareTypedQuery(QueryConfig config);
protected Query prepareUntypedQuery(QueryConfig config) { return null; }
protected void preparePagination(Query query, QueryConfig config) {
if (config.getFirstResult() >= 0) {
query.setFirstResult(config.getFirstResult());
}
if (config.getMaxResults() >= 1) {
query.setMaxResults(config.getMaxResults());
}
}
protected void prepareParameters(Query query, Map<String, Object> parameters, QueryConfig config) {
if (parameters != null) {
for (Map.Entry<String, Object> entry : parameters.entrySet()) {
query.setParameter(entry.getKey(), entry.getValue());
}
}
}
protected void prepareHints(Query query, QueryConfig config) {
if (isCache()) {
// TODO: add support for other jpa provider or let the provider handle the caching (recommended)
if (JpaHelper.isJpaProviderHibernate(getEntityManager())) {
// TODO: hibernate has problems caching queries with embedded types as parameter
// query.setHint("org.hibernate.cacheable", "true");
// query.setHint("org.hibernate.cacheRegion", getCacheRegion());
}
}
if (!hints.isEmpty()) {
for (Map.Entry<String, Object> entry : hints.entrySet()) {
query.setHint(entry.getKey(), entry.getValue());
}
}
}
protected void prepareSingleResult(R result) { }
protected void prepareResult(List<R> result) { }
protected void prepareResultCount(QueryConfig config) { }
protected void executeResultCount() { }
}