package ru.simplex_software.wicket_springdata;
import org.apache.wicket.injection.Injector;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.hibernate.Hibernate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Persistable;
import org.springframework.data.repository.CrudRepository;
import java.io.Serializable;
import java.util.Iterator;
import java.util.Optional;
import java.util.stream.StreamSupport;
/**
* Модель содержит:
* Persistable сущность в прикреплённом состоянии,
* id и класс Persistable сущности в откреплённом состоянии.
*/
public class HibernateModel<T extends Persistable<? extends Serializable>> extends LoadableDetachableModel<T> {
private static final Logger LOG = LoggerFactory.getLogger(HibernateModel.class);
@SpringBean
private RepositoryFinder repositoryFinder;
/**
* Первичный кдюч хранимой сущности
*/
private Serializable id;
/**
* Класс хранимой сущности
*/
private Class<T> tClass;
public HibernateModel() {
init();
}
/**
* Конструктор.
*
* @param entity может быть NULL.
*/
public HibernateModel(T entity) {
super(entity);
init();
setObject(entity);
}
public void setObject(T entity) {
if (entity != null && entity.isNew()) {
throw new IllegalArgumentException("primary key can't be null");
}
super.setObject(entity);
}
/**
* Открепление сущности.
*/
public void onDetach() {
LOG.debug("onDetach start");
// Получаем Persistable сущность.
T entity = getObject();
if (entity == null) {
id = null;
tClass = null;
} else {
id = entity.getId();
tClass = (Class<T>) Hibernate.getClass(entity);
}
LOG.debug("onDetach end");
}
private void init() {
Injector.get().inject(this);
}
@Override
protected T load() {
LOG.debug("load start");
if (isAttached()) {
return getObject();
}
if (tClass == null) {
return null;
}
final CrudRepository<T, Serializable> repository = repositoryFinder.findRepository(tClass);
LOG.trace("repository={}", repository);
Optional<T> optional = repository.findById(id);
return optional.orElseThrow(() -> new RuntimeException("Entity with type " + tClass + " and id " + id + " not found."));
}
/**
* Оборачивает в HibernateModel элементы коллекции, преобразует их к IModel и возвращает итератор.
*/
public static <E extends Persistable<? extends Serializable>> Iterator<IModel<E>> getItemsModels(Iterable<E> iterable) {
return StreamSupport.stream(iterable.spliterator(), false)
.map(HibernateModel::new)
.map(item -> (IModel<E>) item)
.iterator();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (id == null) {
onDetach();
}
if (id == null) {//if no object set
if (o instanceof HibernateModel) {
Object obj = ((HibernateModel) o).getObject();
return obj == null;
}
return false;
}
if (o == null || getClass() != o.getClass()) return false;
HibernateModel<?> that = (HibernateModel<?>) o;
if (that.id == null) {
that.onDetach();
}
if (!id.equals(that.id)) {
return false;
}
return tClass.equals(that.tClass);
}
@Override
public int hashCode() {
if (id == null) {
onDetach(); // Для установки Id
}
if (id == null) { // if no object set
return -1;
} else {
return id.hashCode();
}
}
public RepositoryFinder getRepositoryFinder() {
return repositoryFinder;
}
public void setRepositoryFinder(RepositoryFinder repositoryFinder) {
this.repositoryFinder = repositoryFinder;
}
}