/*
* Copyright (c) 2011, Municipiality of Vienna, Austria
*
* Licensed under the EUPL, Version 1.1 or � as soon they
* will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the
* Licence.
*
* For convenience a plain text copy of the English version
* of the Licence can be found in the file LICENCE.txt in
* the top-level directory of this software distribution.
*
* You may obtain a copy of the Licence in any of 22 European
* Languages at:
*
* http://www.osor.eu/eupl
*
* Unless required by applicable law or agreed to in
* writing, software distributed under the Licence is
* distributed on an "AS IS" basis,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the Licence for the specific language governing
* permissions and limitations under the Licence.
*/
package org.azzyzt.jee.runtime.eao;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import org.azzyzt.jee.runtime.dto.query.OrderByClause;
import org.azzyzt.jee.runtime.dto.query.QuerySpec;
import org.azzyzt.jee.runtime.entity.EntityBase;
import org.azzyzt.jee.runtime.exception.AccessDeniedException;
import org.azzyzt.jee.runtime.exception.EntityInstantiationException;
import org.azzyzt.jee.runtime.exception.EntityNotFoundException;
import org.azzyzt.jee.runtime.exception.InvalidFieldException;
import org.azzyzt.jee.runtime.exception.InvalidIdException;
import org.azzyzt.jee.runtime.exception.NotYetImplementedException;
import org.azzyzt.jee.runtime.exception.QuerySyntaxException;
import org.azzyzt.jee.runtime.meta.TypeMetaInfoInterface;
import org.azzyzt.jee.runtime.util.QueryBuilder;
/**
* The abstract base class of the generated generic entity access objects.
* The generated generic EAO is a stateless session bean, and its only
* purpose is to be a target for injection. All interaction with JPA happens here.
*/
public abstract class EaoBase {
/**
* The <code>EntityManager</code> is injected into the concrete generated
* child class. This abstract method lets the generic methods access the
* persistence context.
*
* @return the <code>EntityManager</code>
*/
public abstract EntityManager getEm();
public void flush() {
getEm().flush();
}
/**
* Fetches an entity by ID or, if it does not exist, fails with an exception.
*
* @param clazz an entity class
* @param id the ID of an entity
* @return the entity
* @throws EntityNotFoundException
*/
public <I, T extends EntityBase<I>> T findOrFail(Class<T> clazz, I id)
throws EntityNotFoundException
{
T e = getEm().find(clazz, id);
if (e == null) {
throw new EntityNotFoundException(clazz.getClass(), id.toString());
}
return e;
}
/**
* A raw version of {@link #findOrFail(Class, Object)} needed in cases when we are definite about the classes,
* but have no way to prove it to the compiler. Used for the "delete" part
* of "storeDelete()".
*
* Order changed because of otherwise identical erasure.
*
* @param clazz an entity class
* @param id the ID of an entity
* @return the entity
* @throws EntityNotFoundException
*/
public Object findOrFail(Object id, Class<?> clazz)
throws EntityNotFoundException
{
Object e = getEm().find(clazz, id);
if (e == null) {
throw new EntityNotFoundException(clazz.getClass(), id.toString());
}
return e;
}
/**
* Fetches an entity by ID or, if it does not exist, creates it.
*
* @param clazz an entity class
* @param id the ID of an entity
* @return the entity
* @throws EntityNotFoundException
* @throws EntityInstantiationException
*/
public <I, T extends EntityBase<I>> T findOrCreate(Class<T> clazz, I id)
throws EntityNotFoundException, EntityInstantiationException
{
T result = null;
if (EntityBase.couldBeIdValue(id)) {
result = getEm().find(clazz, id);
}
if (result == null) {
try {
result = clazz.newInstance();
} catch (InstantiationException e) {
throw new EntityInstantiationException(clazz);
} catch (IllegalAccessException e) {
throw new EntityInstantiationException(clazz);
}
persist(result);
}
return result;
}
/**
* Fetches an entity by ID or, if the ID is invalid or <code>null</code>, fails.
*
* @param clazz an entity class
* @param id the ID of an entity
* @return the entity
* @throws EntityNotFoundException
* @throws InvalidIdException
*/
public <I, T extends EntityBase<I>> T findOrInvalidId(Class<T> clazz, I id)
throws EntityNotFoundException, InvalidIdException
{
T result;
if (EntityBase.couldBeIdValue(id)) {
result = findOrFail(clazz, id);
} else {
throw new InvalidIdException(id.toString());
}
return result;
}
/**
* Fetches an entity by ID or, if not found, returns <code>null</code>.
*
* @param clazz an entity class
* @param id the ID of an entity
* @return the entity or <code>null</code>
* @throws InvalidIdException
*/
public <I, T extends EntityBase<I>> T findOrNull(Class<T> clazz, I id)
throws InvalidIdException
{
T result;
if (EntityBase.couldBeIdValue(id)) {
result = getEm().find(clazz, id);
} else {
throw new InvalidIdException(id.toString());
}
return result;
}
/**
* Stores an entity.
*
* @param entity the entity
*/
public <I, T extends EntityBase<I>> void persist(T entity) {
if (entity.likelyHasId()) {
getEm().merge(entity);
} else {
getEm().persist(entity);
}
}
/**
* Deletes an entity of a given class and ID.
*
* @param clazz an entity class
* @param id the ID of an entity
* @throws EntityNotFoundException
*/
public <I, T extends EntityBase<I>> void delete(Class<T> clazz, I id)
throws EntityNotFoundException {
T e = findOrFail(clazz, id);
getEm().remove(e);
}
/**
* Another version needed in cases when we are definite about the classes,
* but have no way to prove it to the compiler. Used for the "delete" part
* of "storeDelete()".
*
* Order changed because of otherwise identical erasure.
*
* @param id the ID of an entity
* @param clazz an entity class
* @throws EntityNotFoundException
*/
public void delete(Object id, Class<?> clazz)
throws EntityNotFoundException {
Object e = findOrFail(id, clazz);
getEm().remove(e);
}
/**
* Deletes all entities with a name matching a certain wildcard.
*
* @param clazz an entity class
* @param nameWc a name wildcard string
*/
public <I, T extends EntityBase<I>> void deleteByName(Class<T> clazz, String nameWc) {
Query q = getEm().createQuery("delete from "+clazz.getSimpleName()+" where name like :nameWc");
q.setParameter("nameWc", nameWc);
q.executeUpdate();
}
/**
* Returns all entities of a certain class
*
* @param clazz an entity class
* @return a list of entities
*/
@SuppressWarnings("unchecked")
public <I, T extends EntityBase<I>> List<T> all(Class<T> clazz) {
Query q = getEm().createQuery("select c from "+clazz.getSimpleName()+" c");
List<T> result = q.getResultList();
return result;
}
/**
* Returns the result of a typed query. The query is built by a <code>QueryBuilder</code> from
* a <code>QuerySpec</code>.
*
* @param qs a query specification
* @param clazz an entity class
* @param tmi type meta information generated by Azzyzt JEE Tools
* @return a list of entities
* @throws InvalidFieldException
* @throws AccessDeniedException
* @throws QuerySyntaxException
* @throws NotYetImplementedException
*/
public <I, T extends EntityBase<I>> List<T> list(QuerySpec qs, Class<T> clazz, TypeMetaInfoInterface tmi)
throws InvalidFieldException, AccessDeniedException, QuerySyntaxException, NotYetImplementedException
{
QueryBuilder<I, T> qb = new QueryBuilder<I, T>(getEm(), qs, clazz, tmi);
TypedQuery<T> tq = qb.build();
List<T> result = tq.getResultList();
return result;
}
/**
* Returns all entities of a certain class, ordered according to an <code>OrderByClause</code>.
*
* @param clazz an entity class
* @param orderBy an <code>OrderByClause</code>
* @return an ordered list of all entities of the given class
*/
@SuppressWarnings("unchecked")
public <I, T extends EntityBase<I>> List<T> allOrdered(Class<T> clazz, OrderByClause orderBy) {
// orderBy is expected to be validated
Query q = getEm().createQuery("select c from "+clazz.getSimpleName()+" c order by c."
+orderBy.getFieldName()
+(orderBy.isAscending() ? " ASC" : " DESC"));
List<T> result = q.getResultList();
return result;
}
}