package de.rwth.idsg.bikeman.repository;
import com.google.common.base.Optional;
import de.rwth.idsg.bikeman.domain.*;
import de.rwth.idsg.bikeman.domain.CustomerType;
import de.rwth.idsg.bikeman.web.rest.dto.modify.CreateEditPedelecDTO;
import de.rwth.idsg.bikeman.web.rest.dto.view.ViewErrorDTO;
import de.rwth.idsg.bikeman.web.rest.dto.view.ViewPedelecDTO;
import de.rwth.idsg.bikeman.web.rest.exception.DatabaseException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityExistsException;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Root;
import java.util.List;
/**
* Created by sgokay on 21.05.14.
*/
@Repository
@Slf4j
public class PedelecRepositoryImpl implements PedelecRepository {
@PersistenceContext private EntityManager em;
@Override
@Transactional(readOnly = true)
public List<ViewPedelecDTO> findAll() throws DatabaseException {
CriteriaBuilder builder = em.getCriteriaBuilder();
List<ViewPedelecDTO> list = findPedelecsInTransaction(builder, CustomerType.CUSTOMER);
list.addAll(findPedelecsInTransaction(builder, CustomerType.MAJOR_CUSTOMER));
list.addAll(findStationaryPedelecs(builder));
return list;
}
@SuppressWarnings("unchecked")
private List<ViewPedelecDTO> findPedelecsInTransaction(CriteriaBuilder builder, CustomerType customerType) {
CriteriaQuery<ViewPedelecDTO> criteria = builder.createQuery(ViewPedelecDTO.class);
Root<Pedelec> pedelec = criteria.from(Pedelec.class);
Join<Pedelec, Transaction> transaction = pedelec.join(Pedelec_.transactions, JoinType.LEFT);
Join<Transaction, CardAccount> cardAccount = transaction.join(Transaction_.cardAccount, JoinType.LEFT);
Join user = cardAccount.join(CardAccount_.user, JoinType.LEFT);
Join<Transaction, StationSlot> fromStationSlot = transaction.join(Transaction_.fromSlot, JoinType.LEFT);
Join<StationSlot, Station> fromStation = fromStationSlot.join(StationSlot_.station, JoinType.LEFT);
Join<Pedelec, PedelecChargingStatus> chargingStatus = pedelec.join(Pedelec_.chargingStatus, JoinType.LEFT);
switch (customerType) {
case CUSTOMER:
criteria.select(
builder.construct(
ViewPedelecDTO.class,
pedelec.get(Pedelec_.pedelecId),
pedelec.get(Pedelec_.manufacturerId),
chargingStatus.get(PedelecChargingStatus_.batteryStateOfCharge),
pedelec.get(Pedelec_.state),
pedelec.get(Pedelec_.inTransaction),
cardAccount.get(CardAccount_.cardId),
user.get(Customer_.customerId),
user.get(Customer_.firstname),
user.get(Customer_.lastname),
fromStation.get(Station_.stationId),
fromStationSlot.get(StationSlot_.stationSlotPosition),
transaction.get(Transaction_.startDateTime)
)
);
break;
case MAJOR_CUSTOMER:
criteria.select(
builder.construct(
ViewPedelecDTO.class,
pedelec.get(Pedelec_.pedelecId),
pedelec.get(Pedelec_.manufacturerId),
chargingStatus.get(PedelecChargingStatus_.batteryStateOfCharge),
pedelec.get(Pedelec_.state),
pedelec.get(Pedelec_.inTransaction),
cardAccount.get(CardAccount_.cardId),
user.get(MajorCustomer_.name),
fromStation.get(Station_.stationId),
fromStationSlot.get(StationSlot_.stationSlotPosition),
transaction.get(Transaction_.startDateTime)
)
);
break;
}
criteria.where(
builder.and(
builder.equal(cardAccount.get(CardAccount_.ownerType), customerType),
builder.equal(pedelec.get(Pedelec_.inTransaction), true),
builder.isNull(transaction.get(Transaction_.endDateTime)),
builder.isNull(transaction.get(Transaction_.toSlot))
));
return em.createQuery(criteria).getResultList();
}
private List<ViewPedelecDTO> findStationaryPedelecs(CriteriaBuilder builder) {
CriteriaQuery<ViewPedelecDTO> criteria = builder.createQuery(ViewPedelecDTO.class);
Root<Pedelec> pedelec = criteria.from(Pedelec.class);
Join<Pedelec, StationSlot> stationSlot = pedelec.join(Pedelec_.stationSlot, JoinType.LEFT);
Join<StationSlot, Station> station = stationSlot.join(StationSlot_.station, JoinType.LEFT);
Join<Pedelec, PedelecChargingStatus> chargingStatus = pedelec.join(Pedelec_.chargingStatus, JoinType.LEFT);
criteria.select(
builder.construct(
ViewPedelecDTO.class,
pedelec.get(Pedelec_.pedelecId),
pedelec.get(Pedelec_.manufacturerId),
chargingStatus.get(PedelecChargingStatus_.batteryStateOfCharge),
pedelec.get(Pedelec_.state),
pedelec.get(Pedelec_.inTransaction),
station.get(Station_.stationId),
station.get(Station_.name),
stationSlot.get(StationSlot_.stationSlotPosition),
chargingStatus.get(PedelecChargingStatus_.timestamp),
chargingStatus.get(PedelecChargingStatus_.state)
)
).where(builder.equal(pedelec.get(Pedelec_.inTransaction), false));
return em.createQuery(criteria).getResultList();
}
@Override
@Transactional(readOnly = true)
public ViewPedelecDTO findOneDTO(Long pedelecId) throws DatabaseException {
final String q = "SELECT new de.rwth.idsg.bikeman.web.rest.dto.view." +
"ViewPedelecDTO(p.pedelecId, p.manufacturerId, cs.batteryStateOfCharge, p.state, p.inTransaction) " +
"FROM Pedelec p " +
"JOIN p.chargingStatus cs " +
"WHERE p.pedelecId = :pedelecId";
try {
return em.createQuery(q, ViewPedelecDTO.class)
.setParameter("pedelecId", pedelecId)
.getSingleResult();
} catch (Exception e) {
throw new DatabaseException("Failed to find pedelec with pedelecId " + pedelecId, e);
}
}
@Override
@Transactional(readOnly = true)
public Pedelec findOne(long pedelecId) throws DatabaseException {
return getPedelecEntity(pedelecId);
}
@Transactional(readOnly = true)
public Pedelec findByManufacturerId(String manufacturerId) throws DatabaseException {
final String q = "SELECT p FROM Pedelec p WHERE p.manufacturerId = :manufacturerId";
try {
return em.createQuery(q, Pedelec.class)
.setParameter("manufacturerId", manufacturerId)
.getSingleResult();
} catch (Exception e) {
throw new DatabaseException("Failed to find pedelec with manufacturerId " + manufacturerId, e);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public List<Pedelec> findByStation(String stationManufacturerId) throws DatabaseException {
final String q = "select p from Pedelec p where p.stationSlot.station.manufacturerId = :stationManufacturerId";
try {
return em.createQuery(q, Pedelec.class)
.setParameter("stationManufacturerId", stationManufacturerId)
.getResultList();
} catch (Exception e) {
throw new DatabaseException("Failed to find pedelecs by stationManufacturerId " + stationManufacturerId, e);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public List<String> findManufacturerIdsByStation(String stationManufacturerId) throws DatabaseException {
final String q = "select p.manufacturerId from Pedelec p where p.stationSlot.station.manufacturerId = :stationManufacturerId";
try {
return em.createQuery(q, String.class)
.setParameter("stationManufacturerId", stationManufacturerId)
.getResultList();
} catch (Exception e) {
throw new DatabaseException("Failed to find pedelecs by stationManufacturerId " + stationManufacturerId, e);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public Pedelec findByStationSlot(String stationSlotManufacturerId) throws DatabaseException {
final String q = "SELECT p FROM Pedelec p WHERE p.stationSlot.manufacturerId = :manufacturerId";
try {
return em.createQuery(q, Pedelec.class)
.setParameter("manufacturerId", stationSlotManufacturerId)
.getSingleResult();
} catch (Exception e) {
throw new DatabaseException("Failed to find pedelec with stationSlotManufacturerId " + stationSlotManufacturerId, e);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public Optional<Pedelec> findPedelecsByStationSlot(String stationManufacturerId, String stationSlotManufacturerId)
throws DatabaseException {
final String q = "SELECT p FROM Pedelec p " +
"WHERE p.stationSlot.manufacturerId = :stationSlotManufacturerId " +
"AND p.stationSlot.station.manufacturerId = :stationManufacturerId";
try {
Pedelec p = em.createQuery(q, Pedelec.class)
.setParameter("stationSlotManufacturerId", stationSlotManufacturerId)
.setParameter("stationManufacturerId", stationManufacturerId)
.getSingleResult();
return Optional.of(p);
} catch (NoResultException e) {
// Do nothing, this is a valid outcome
} catch (Exception e) {
log.error("Error occurred", e);
}
return Optional.absent();
}
@Override
@Transactional(readOnly = true)
public List<ViewErrorDTO> findErrors() throws DatabaseException {
String q = "SELECT new de.rwth.idsg.bikeman.web.rest.dto.view.ViewErrorDTO" +
"(p.pedelecId, p.manufacturerId, p.errorCode, p.errorInfo, p.updated) " +
"FROM Pedelec p where not (p.errorCode = '') and p.errorCode is not null";
try {
return em.createQuery(q, ViewErrorDTO.class)
.getResultList();
} catch (Exception e) {
log.error("Error occurred", e);
throw new DatabaseException("PedelecRepository exception while looking for errors");
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void create(CreateEditPedelecDTO dto) throws DatabaseException {
Pedelec pedelec = new Pedelec();
setFields(pedelec, dto);
try {
em.persist(pedelec);
log.debug("Created new pedelec {}", pedelec);
} catch (EntityExistsException e) {
throw new DatabaseException("This pedelec exists already.", e);
} catch (Exception e) {
throw new DatabaseException("Failed to create a new pedelec.", e);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void update(CreateEditPedelecDTO dto) throws DatabaseException {
final Long pedelecId = dto.getPedelecId();
if (pedelecId == null) {
return;
}
Pedelec pedelec = getPedelecEntity(pedelecId);
setFields(pedelec, dto);
try {
em.merge(pedelec);
log.debug("Updated pedelec {}", pedelec);
} catch (Exception e) {
throw new DatabaseException("Failed to update pedelec with pedelecId " + pedelecId, e);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void delete(long pedelecId) throws DatabaseException {
Pedelec pedelec = getPedelecEntity(pedelecId);
try {
em.remove(pedelec);
log.debug("Deleted pedelec {}", pedelec);
} catch (Exception e) {
throw new DatabaseException("Failed to delete pedelec with pedelec " + pedelecId, e);
}
}
/**
* Returns a pedelec, or throws exception when no pedelec exists.
*/
@Transactional(readOnly = true)
private Pedelec getPedelecEntity(long pedelecId) throws DatabaseException {
Pedelec pedelec = em.find(Pedelec.class, pedelecId);
if (pedelec == null) {
throw new DatabaseException("No pedelec with pedelecId " + pedelecId);
} else {
return pedelec;
}
}
/**
* This method sets the fields of the pedelec to the values in DTO.
* <p>
* Important: The ID is not set!
*/
private void setFields(Pedelec pedelec, CreateEditPedelecDTO dto) {
pedelec.setState(dto.getState());
pedelec.setManufacturerId(dto.getManufacturerId());
PedelecChargingStatus status = new PedelecChargingStatus();
status.setPedelec(pedelec);
pedelec.setChargingStatus(status);
}
}