package ilarkesto.persistence;
import ilarkesto.auth.AUser;
import ilarkesto.auth.AUserDao;
import ilarkesto.auth.Auth;
import ilarkesto.base.Reflect;
import ilarkesto.base.Utl;
import ilarkesto.base.time.DateAndTime;
import ilarkesto.core.logging.Log;
import ilarkesto.di.Context;
import ilarkesto.fp.Predicate;
import ilarkesto.id.IdentifiableResolver;
import ilarkesto.search.SearchResultsConsumer;
import ilarkesto.search.Searchable;
import ilarkesto.search.Searcher;
import ilarkesto.base.Iconized;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public abstract class ADao<E extends AEntity> extends ADatobManager<E> implements IdentifiableResolver<E>, Searcher,
DaoListener, Iconized {
private static final Log LOG = Log.get(ADao.class);
private Predicate<Class> entityTypeFilter;
private String icon;
// --- ---
@Override
public void onDatobModified(E entity, String comment) {
entity.setLastModified(DateAndTime.now());
// don's save new entities
if (!isPersistent(entity)) return;
LOG.info("Entity modified:", Utl.toStringWithType(entity), "->", comment);
saveEntity(entity);
}
@Override
public void onMissingMaster(E entity) {
deleteEntity(entity);
throw new EnsureIntegrityCompletedException();
}
// --- basic ---
public abstract String getEntityName();
public abstract Class getEntityClass();
public Map<String, Class> getAliases() {
return Collections.emptyMap();
}
private boolean isPersistent(E entity) {
return transactionService.isPersistent(entity.getId());
}
public final Predicate<Class> getEntityTypeFilter() {
if (entityTypeFilter == null) {
entityTypeFilter = new Predicate<Class>() {
public boolean test(Class parameter) {
return parameter.isAssignableFrom(getEntityClass());
}
};
}
return entityTypeFilter;
}
@Override
public String getIcon() {
if (icon == null) {
icon = (String) Reflect.getFieldValue(getEntityClass(), "ICON");
if (icon == null) icon = getEntityName();
}
return icon;
}
public int getEntitiesCount(Predicate<E> predicate) {
return transactionService.getEntitiesCount(getEntityTypeFilter(), (Predicate<AEntity>) predicate);
}
public E getEntity(Predicate<E> predicate) {
return (E) transactionService.getEntity(getEntityTypeFilter(), (Predicate<AEntity>) predicate);
}
public final Set<E> getEntities(Predicate<E> filter) {
// long start = System.currentTimeMillis();
Set<E> result = (Set<E>) transactionService.getEntities(getEntityTypeFilter(), (Predicate<AEntity>) filter);
// long time = System.currentTimeMillis() - start;
// if (time > 2000) throw new RuntimeException("getEntities took too
// long. fix it!");
return result;
}
@Override
public E getById(String id) {
if (id == null) throw new RuntimeException("id must not be null");
E entity = (E) transactionService.getById(id);
if (entity == null) throw new EntityDoesNotExistException(id);
return entity;
}
@Deprecated
public E getEntityById(String id) {
return getById(id);
}
@Override
public List<E> getByIds(Collection<String> entitiesIds) {
Set<String> ids = new HashSet<String>(entitiesIds);
List<E> result = (List<E>) transactionService.getByIds(entitiesIds);
if (result.size() != ids.size()) {
for (E entity : result) {
ids.remove(entity.getId());
}
throw new EntityDoesNotExistException((String) ids.toArray()[0]);
}
return result;
}
public Set<E> getByIdsAsSet(Collection<String> entitiesIds) {
return new HashSet<E>(getByIds(entitiesIds));
}
@Deprecated
public List<E> getEntitiesByIds(Collection<String> entitiesIds) {
return getByIds(entitiesIds);
}
public Set<E> getEntitiesVisibleForUser(final AUser user) {
return getEntities(new Predicate<E>() {
public boolean test(E e) {
return Auth.isVisible(e, user);
}
});
}
public Set<E> getEntities() {
return (Set<E>) transactionService.getEntities(getEntityTypeFilter(), null);
}
public void deleteEntity(E entity) {
transactionService.deleteEntity(entity);
daoService.fireEntityDeleted(entity);
}
public void saveEntity(E entity) {
transactionService.saveEntity(entity);
daoService.fireEntitySaved(entity);
}
public E newEntityInstance() {
E entity;
try {
entity = (E) getEntityClass().newInstance();
} catch (InstantiationException ex) {
throw new RuntimeException(ex);
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
}
entity.setLastModified(DateAndTime.now());
transactionService.registerEntity(entity);
return entity;
}
public E newEntityInstance(String id) {
E entity = newEntityInstance();
entity.setId(id);
return entity;
}
public void ensureIntegrity() {
if (!initialized) throw new RuntimeException("Not initialized!");
Class clazz = getEntityClass();
LOG.info("Ensuring integrity:", clazz.getSimpleName());
for (E entity : getEntities()) {
try {
entity.ensureIntegrity();
} catch (EnsureIntegrityCompletedException ex) {
continue;
} catch (Throwable ex) {
throw new RuntimeException("Ensuring integrity for " + clazz.getSimpleName() + ":" + entity.getId()
+ " failed.", ex);
}
}
}
public void entityDeleted(EntityEvent event) {
AEntity entity = event.getEntity();
for (AEntity e : getEntities()) {
try {
e.repairDeadReferences(entity.getId());
} catch (EnsureIntegrityCompletedException ex) {
continue;
}
}
}
public void entitySaved(EntityEvent event) {}
public void feed(final SearchResultsConsumer searchBox) {
if (!Searchable.class.isAssignableFrom(getEntityClass())) return;
for (AEntity entity : getEntities(new Predicate<E>() {
public boolean test(E e) {
return Auth.isVisible(e, searchBox.getSearcher()) && e instanceof Searchable
&& Persist.matchesKeys(e, searchBox.getKeys());
}
})) {
searchBox.addEntity(entity);
}
}
protected final TransactionService getTransactionService() {
return transactionService;
}
// ---
protected Set<Class> getValueObjectClasses() {
return Collections.emptySet();
}
@Override
public String toString() {
String entityName = getEntityName();
if (entityName == null) return entityName + "Dao";
return getClass().getName();
}
// --------------------
// --- dependencies ---
// --------------------
private volatile boolean initialized;
public synchronized final void initialize(Context context) {
if (initialized) throw new RuntimeException("Already initialized!");
Class entityClass = getEntityClass();
context.autowireClass(entityClass);
for (Class c : getValueObjectClasses())
context.autowireClass(c);
Field daoField;
try {
daoField = entityClass.getDeclaredField("dao");
boolean accessible = daoField.isAccessible();
if (!accessible) daoField.setAccessible(true);
try {
daoField.set(null, this);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (NullPointerException ex) {
throw new RuntimeException("Setting dao field failed. Is it static?", ex);
}
if (!accessible) daoField.setAccessible(false);
} catch (SecurityException ex) {
throw new RuntimeException(ex);
} catch (NoSuchFieldException ex) {
// nop
}
initialized = true;
}
private DaoService daoService;
public final void setDaoService(DaoService daoService) {
this.daoService = daoService;
}
public final DaoService getDaoService() {
return daoService;
}
private TransactionService transactionService;
public final void setTransactionService(TransactionService transactionService) {
this.transactionService = transactionService;
}
protected AUserDao userDao;
public final void setUserDao(AUserDao userDao) {
this.userDao = userDao;
}
}