/**
* Copyright 2010 CosmoCode GmbH
*
* 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 de.cosmocode.palava.entity;
import com.google.inject.Provider;
import de.cosmocode.palava.jpa.Transactional;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import java.util.List;
/**
* Abstract skeleton implementation of the {@link ReadOnlyEntityService} interface.
*
* @author Willi Schoenborn
* @param <T> the generic entity type
*/
public abstract class AbstractReadOnlyEntityService<T> implements ReadOnlyEntityService<T> {
/**
* Provides an {@link EntityManager} this implementation uses to do it's
* work. Implementations will ususally delegate to an injected {@link Provider}.
*
* @return an {@link EntityManager}
*/
protected abstract EntityManager entityManager();
/**
* Provides the class object of this entity type.
*
* @return this entity type's class object
*/
protected abstract Class<T> entityClass();
@Transactional
@Override
public T get(Object identifier) {
return entityManager().find(entityClass(), identifier);
}
@Transactional
@Override
public T read(Object identifier) {
final T entity = get(identifier);
if (entity == null) {
throw new PersistenceException(String.format("No entity found for id #%s", identifier));
} else {
return entity;
}
}
@Transactional
@Override
@SuppressWarnings("unchecked")
public T read(Query query, Object... parameters) {
return (T) prepare(query, parameters).getSingleResult();
}
@Override
public T read(TypedQuery<T> query, Object... parameters) {
return prepare(query, parameters).getSingleResult();
}
@Transactional
@Override
@SuppressWarnings("unchecked")
public T read(String queryName, Object... parameters) {
return (T) prepare(entityManager().createNamedQuery(queryName), parameters).getSingleResult();
}
@Transactional
@Override
public T reference(long identifier) {
return entityManager().getReference(entityClass(), identifier);
}
@Transactional
@Override
@SuppressWarnings("unchecked")
public List<T> list(Query query, Object... parameters) {
return (List<T>) prepare(query, parameters).getResultList();
}
@Transactional
@Override
public List<T> list(TypedQuery<T> query, Object... parameters) {
return prepare(query, parameters).getResultList();
}
@Transactional
@Override
@SuppressWarnings("unchecked")
public List<T> list(String queryName, Object... parameters) {
return (List<T>) prepare(entityManager().createNamedQuery(queryName), parameters).getResultList();
}
/**
* Creates a typed query using {@link #entityClass()}. This is like a <code>SELECT * FROM T</code>.
*
* @return a typed query without any restrictions
*/
TypedQuery<T> getTypedQuery() {
final CriteriaBuilder builder = entityManager().getCriteriaBuilder();
final CriteriaQuery<T> criteria = builder.createQuery(entityClass());
criteria.from(entityClass());
return entityManager().createQuery(criteria);
}
@Transactional
@Override
public List<T> iterate() {
return getTypedQuery().getResultList();
}
@Override
public Iterable<T> iterate(int batchSize) {
final TypedQuery<T> query = getTypedQuery();
return iterate(query, batchSize);
}
@Override
public Iterable<T> iterate(TypedQuery<T> query, int batchSize) {
return new PreloadingIterable<T>(query, batchSize);
}
@Transactional
@Override
@SuppressWarnings("unchecked")
public <P> P projection(Query query, Object... parameters) {
return (P) prepare(query, parameters).getSingleResult();
}
@Override
public <P> P projection(TypedQuery<P> query, Object... parameters) {
return prepare(query, parameters).getSingleResult();
}
@Transactional
@Override
@SuppressWarnings("unchecked")
public <P> P projection(String queryName, Object... parameters) {
return (P) prepare(entityManager().createNamedQuery(queryName), parameters).getSingleResult();
}
@Transactional
@Override
@SuppressWarnings("unchecked")
public <P> P[] projections(Query query, Object... parameters) {
return (P[]) prepare(query, parameters).getSingleResult();
}
@Transactional
@Override
@SuppressWarnings("unchecked")
public <P> P[] projections(String queryName, Object... parameters) {
return (P[]) prepare(entityManager().createNamedQuery(queryName), parameters).getSingleResult();
}
@Transactional
@Override
@SuppressWarnings("unchecked")
public <P> List<P> projectionList(Query query, Object... parameters) {
return (List<P>) prepare(query, parameters).getResultList();
}
@Override
public <P> List<P> projectionList(TypedQuery<P> query, Object... parameters) {
return prepare(query, parameters).getResultList();
}
@Transactional
@Override
@SuppressWarnings("unchecked")
public <P> List<P> projectionList(String queryName, Object... parameters) {
return (List<P>) prepare(entityManager().createNamedQuery(queryName), parameters).getResultList();
}
@Transactional
@Override
@SuppressWarnings("unchecked")
public <P> List<P[]> projectionsList(Query query, Object... parameters) {
return (List<P[]>) prepare(query, parameters).getResultList();
}
@Transactional
@Override
@SuppressWarnings("unchecked")
public <P> List<P[]> projectionsList(String queryName, Object... parameters) {
return (List<P[]>) prepare(entityManager().createNamedQuery(queryName), parameters).getResultList();
}
private void doPrepare(Query query, Object[] parameters) {
for (int i = 0; i < parameters.length; i++) {
query.setParameter(i + 1, parameters[i]);
}
}
@Override
public Query prepare(Query query, Object... parameters) {
doPrepare(query, parameters);
return query;
}
@Override
public <X> TypedQuery<X> prepare(TypedQuery<X> query, Object... parameters) {
doPrepare(query, parameters);
return query;
}
@Override
public TypedQuery<T> prepare(String queryName, Object... parameters) {
return prepare(entityManager().createNamedQuery(queryName, entityClass()), parameters);
}
}