/*
* Copyright 2002-2007 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.internna.iwebmvc.core.dao;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.hibernate.search.annotations.IndexedEmbedded;
import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.FullTextQuery;
import org.hibernate.search.jpa.Search;
import org.internna.iwebmvc.core.IWebMvcException;
import org.internna.iwebmvc.model.DomainEntity;
import org.internna.iwebmvc.model.UUID;
import org.internna.iwebmvc.utils.Assert;
import org.internna.iwebmvc.utils.ClassUtils;
import org.springframework.transaction.annotation.Transactional;
/**
*
* @author Jose Noheda
* @since 1.0
*/
public abstract class AbstractDAO implements DAO {
protected final Log log = LogFactory.getLog(getClass());
protected abstract EntityManager getEntityManager();
protected void prepareQuery(Query query, int offset, int max, Map<String, Object> parameters) {
if ((parameters != null) && (parameters.size() > 0))
for (String parameter : parameters.keySet())
query.setParameter(parameter, parameters.get(parameter));
query.setFirstResult(offset > 0 ? offset : 0);
query.setMaxResults(max > 0 ? max : MAX_RESULTS);
}
@Transactional
public void create(DomainEntity entity) {
Assert.notNull(entity);
Assert.isNull(entity.getId());
getEntityManager().persist(entity);
getEntityManager().flush();
}
@Override
@Transactional(readOnly = true)
public <T extends DomainEntity> List<T> find(Class<T> entity, int offset, int max) {
Assert.notNull(entity);
return findByNamedQuery(entity.getSimpleName() + ".findAll", offset, max, null);
}
@Override
@Transactional(readOnly = true)
public <T extends DomainEntity> List<T> findByNamedQuery(String query, int offset, int max, Map<String, Object> parameters) {
return findByQuery(getEntityManager().createNamedQuery(query), offset, max, parameters);
}
@Override
@Transactional(readOnly = true)
public <T extends DomainEntity> List<T> findByQuery(String query, int offset, int max, Map<String, Object> parameters) {
return findByQuery(getEntityManager().createQuery(query), offset, max, parameters);
}
@SuppressWarnings("unchecked")
@Transactional(readOnly = true)
protected <T extends DomainEntity> List<T> findByQuery(Query query, int offset, int max, Map<String, Object> parameters) {
Assert.notNull(query);
prepareQuery(query, offset, max, parameters);
return (List<T>) query.getResultList();
}
@Override
@Transactional(readOnly = true)
public <T extends DomainEntity> T find(Class<T> entityClass, UUID pk) {
Assert.notNull(pk);
Assert.notNull(entityClass);
T entity = null;
try {
entity = getEntityManager().find(entityClass, pk);
} catch (Exception ex) {
if (log.isWarnEnabled()) log.warn("Could not retrieve entity [" + entityClass + "] with primary key [" + pk + "]: " + ex.getMessage());
}
return entity;
}
@Override
@Transactional
public DomainEntity update(DomainEntity entity) {
Assert.notNull(entity);
return getEntityManager().merge(entity);
}
@Override
@Transactional
public void remove(DomainEntity entity) {
Assert.notNull(entity);
getEntityManager().remove(entity);
}
@Override
@Transactional
public <T extends DomainEntity> T getReference(Class<T> entityClass, UUID pk) {
Assert.notNull(pk);
Assert.notNull(entityClass);
return getEntityManager().getReference(entityClass, pk);
}
@Override
@Transactional(readOnly = true)
public Object executeQuery(String query) {
Assert.hasText(query);
return executeQuery(query, 0, MAX_RESULTS, null);
}
@Override
@SuppressWarnings("unchecked")
@Transactional(readOnly = true)
public List<Object[]> executeQuery(String query, int offset, int max, Map<String, Object> parameters) {
Assert.hasText(query);
Query q = getEntityManager().createQuery(query);
prepareQuery(q, offset, max, parameters);
return q.getResultList();
}
protected String[] getAllIndexedFields(Class<?> clazz, String field) {
List<String> fields = new ArrayList<String>();
if ("allentityfields".equals(field)) {
for (Field f : ClassUtils.getFields(clazz)) {
if (f.getAnnotation(org.hibernate.search.annotations.Field.class) != null) fields.add(f.getName());
if (f.getAnnotation(IndexedEmbedded.class) != null) {
String[] subfields;
Class<?> fieldClass = f.getType();
if (Collection.class.isAssignableFrom(fieldClass)) {
ParameterizedType coltype = (ParameterizedType) f.getGenericType();
subfields = getAllIndexedFields((Class<?>) coltype.getActualTypeArguments()[0], "allentityfields");
} else subfields = getAllIndexedFields(fieldClass, "allentityfields");
for (String sf : subfields) fields.add(f.getName() + "." + sf);
}
}
} else fields.add(field);
return fields.toArray(new String[0]);
}
@Override
@SuppressWarnings("unchecked")
@Transactional(readOnly = true)
public <T extends DomainEntity> List<T> search(Class<T> clazz, String field, String query, int offset, int number) {
FullTextEntityManager fullTextEntityManager = Search.createFullTextEntityManager(getEntityManager());
MultiFieldQueryParser parser = new MultiFieldQueryParser(getAllIndexedFields(clazz, field), new StandardAnalyzer());
try {
org.apache.lucene.search.Query parsedquery = parser.parse(query.trim().replaceAll(" ", "* ") + "*");
FullTextQuery hq = fullTextEntityManager.createFullTextQuery(parsedquery, clazz);
hq.setMaxResults(number > 0 ? number : MAX_RESULTS);
hq.setFirstResult(offset > 0 ? offset : 0);
return hq.getResultList();
} catch (Exception ex) {
throw new IWebMvcException("Could not perform search", ex);
}
}
@Override
@Transactional
public void flush() {
getEntityManager().flush();
}
}