package de.rwth.idsg.bikeman.psinterface.rest;
import com.google.common.base.Optional;
import com.google.common.util.concurrent.Striped;
import de.rwth.idsg.bikeman.psinterface.Utils;
import de.rwth.idsg.bikeman.psinterface.dto.request.BootNotificationDTO;
import de.rwth.idsg.bikeman.psinterface.dto.request.CardActivationDTO;
import de.rwth.idsg.bikeman.psinterface.dto.request.CardActivationStatusDTO;
import de.rwth.idsg.bikeman.psinterface.dto.request.ChargingStatusDTO;
import de.rwth.idsg.bikeman.psinterface.dto.request.CustomerAuthorizeDTO;
import de.rwth.idsg.bikeman.psinterface.dto.request.FirmwareStatusDTO;
import de.rwth.idsg.bikeman.psinterface.dto.request.LogsStatusDTO;
import de.rwth.idsg.bikeman.psinterface.dto.request.PedelecStatusDTO;
import de.rwth.idsg.bikeman.psinterface.dto.request.StartTransactionDTO;
import de.rwth.idsg.bikeman.psinterface.dto.request.StationStatusDTO;
import de.rwth.idsg.bikeman.psinterface.dto.request.StopTransactionDTO;
import de.rwth.idsg.bikeman.psinterface.dto.response.AuthorizeConfirmationDTO;
import de.rwth.idsg.bikeman.psinterface.dto.response.BootConfirmationDTO;
import de.rwth.idsg.bikeman.psinterface.dto.response.CardActivationResponseDTO;
import de.rwth.idsg.bikeman.psinterface.dto.response.HeartbeatDTO;
import de.rwth.idsg.bikeman.psinterface.exception.PsErrorCode;
import de.rwth.idsg.bikeman.psinterface.exception.PsException;
import de.rwth.idsg.bikeman.service.CardAccountService;
import de.rwth.idsg.bikeman.web.rest.exception.DatabaseException;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.util.List;
import java.util.concurrent.locks.Lock;
/**
* Created by swam on 31/07/14.
*/
@RestController
@RequestMapping(value = "/psi", produces = MediaType.APPLICATION_JSON_VALUE)
@Slf4j
public class PsiResource {
@Inject private PsiService psiService;
@Inject private CardAccountService cardAccountService;
private final Striped<Lock> stationLocks = Striped.lock(25);
private static final String BOOT_NOTIFICATION_PATH = "/boot";
private static final String AUTHORIZE_PATH = "/authorize";
private static final String HEARTBEAT_PATH = "/heartbeat";
private static final String ACTIVATE_CARD_PATH = "/activate-card";
private static final String AVAIL_PEDELECS_PATH = "/available-pedelecs";
private static final String CARD_ACTIVATION_STATUS_PATH = "/status/card-activation";
private static final String STATION_STATUS_PATH = "/status/station";
private static final String PEDELEC_STATUS_PATH = "/status/pedelec";
private static final String CHARGING_STATUS_PATH = "/status/charging";
private static final String FIRMWARE_STATUS_PATH = "/status/firmware";
private static final String LOGS_STATUS_PATH = "/status/logs";
private static final String TRANSACTION_START_PATH = "/transaction/start";
private static final String TRANSACTION_STOP_PATH = "/transaction/stop";
// -------------------------------------------------------------------------
// Station
// -------------------------------------------------------------------------
@RequestMapping(value = BOOT_NOTIFICATION_PATH, method = RequestMethod.POST)
public BootConfirmationDTO bootNotification(@RequestBody BootNotificationDTO bootNotificationDTO,
HttpServletRequest request) throws DatabaseException {
String stationId = Utils.getFrom(request);
log.info("[From: {}] Received bootNotification {}", stationId, bootNotificationDTO);
BootConfirmationDTO dto;
Lock l = stationLocks.get(stationId);
l.lock();
try {
dto = psiService.handleBootNotification(bootNotificationDTO);
} finally {
l.unlock();
}
log.debug("bootNotification returns {}", dto);
return dto;
}
@RequestMapping(value = HEARTBEAT_PATH, method = RequestMethod.GET)
public HeartbeatDTO heartbeat(HttpServletRequest request) {
String stationId = Utils.getFrom(request);
log.debug("[From: {}] Received heartbeat", stationId);
HeartbeatDTO heartbeatDTO = new HeartbeatDTO();
heartbeatDTO.setTimestamp(DateTime.now());
return heartbeatDTO;
}
@RequestMapping(value = AVAIL_PEDELECS_PATH, method = RequestMethod.GET)
public List<String> getAvailablePedelecs(@RequestParam(value = "cardId", required = false) String cardId,
HttpServletRequest request) throws DatabaseException {
String stationId = Utils.getFrom(request);
log.info("[From: {}] Received getAvailablePedelecs for cardId '{}'", stationId, cardId);
List<String> list;
Lock l = stationLocks.get(stationId);
l.lock();
try {
list = psiService.getAvailablePedelecs(stationId, cardId);
} finally {
l.unlock();
}
log.debug("getAvailablePedelecs returns {}", list);
return list;
}
// -------------------------------------------------------------------------
// User
// -------------------------------------------------------------------------
@RequestMapping(value = ACTIVATE_CARD_PATH, method = RequestMethod.POST)
public CardActivationResponseDTO activateCard(@RequestBody CardActivationDTO cardActivationDTO,
HttpServletRequest request, HttpServletResponse response) {
String stationId = Utils.getFrom(request);
log.info("[From: {}] Received activateCard {}", stationId, cardActivationDTO);
Optional<CardActivationResponseDTO> optional;
Lock l = stationLocks.get(stationId);
l.lock();
try {
optional = cardAccountService.activateCardAccount(cardActivationDTO);
} finally {
l.unlock();
}
if (optional.isPresent()) {
return optional.get();
} else {
throw new PsException("Credentials are not accepted", PsErrorCode.CONSTRAINT_FAILED);
}
}
@RequestMapping(value = AUTHORIZE_PATH, method = RequestMethod.POST)
public AuthorizeConfirmationDTO authorize(@RequestBody CustomerAuthorizeDTO customerAuthorizeDTO,
HttpServletRequest request) throws DatabaseException {
String stationId = Utils.getFrom(request);
log.info("[From: {}] Received authorize {}", stationId, customerAuthorizeDTO);
AuthorizeConfirmationDTO dto;
Lock l = stationLocks.get(stationId);
l.lock();
try {
dto = psiService.handleAuthorize(customerAuthorizeDTO);
} finally {
l.unlock();
}
log.debug("authorize returns {}", dto);
return dto;
}
// -------------------------------------------------------------------------
// Transaction
// -------------------------------------------------------------------------
@RequestMapping(value = TRANSACTION_START_PATH, method = RequestMethod.POST)
public void startTransaction(@RequestBody StartTransactionDTO startTransactionDTO,
HttpServletRequest request) throws DatabaseException {
String stationId = Utils.getFrom(request);
log.info("[From: {}] Received startTransaction: {}", stationId, startTransactionDTO);
Lock l = stationLocks.get(stationId);
l.lock();
try {
psiService.handleStartTransaction(startTransactionDTO);
} finally {
l.unlock();
}
}
@RequestMapping(value = TRANSACTION_STOP_PATH, method = RequestMethod.POST)
public void stopTransaction(@RequestBody StopTransactionDTO stopTransactionDTO,
HttpServletRequest request) throws DatabaseException {
String stationId = Utils.getFrom(request);
log.info("[From: {}] Received stopTransaction: {}", stationId, stopTransactionDTO);
Lock l = stationLocks.get(stationId);
l.lock();
try {
psiService.handleStopTransaction(stopTransactionDTO);
} finally {
l.unlock();
}
}
// -------------------------------------------------------------------------
// Status
// -------------------------------------------------------------------------
@RequestMapping(value = CARD_ACTIVATION_STATUS_PATH, method = RequestMethod.POST)
public void stationCardActivationNotification(@RequestBody CardActivationStatusDTO dto,
HttpServletRequest request) {
String stationId = Utils.getFrom(request);
log.info("[From: {}] Received cardActivationNotification: {}", stationId, dto);
Lock l = stationLocks.get(stationId);
l.lock();
try {
cardAccountService.setCardOperative(dto);
} finally {
l.unlock();
}
}
@RequestMapping(value = STATION_STATUS_PATH, method = RequestMethod.POST)
public void stationStatusNotification(@RequestBody StationStatusDTO stationStatusDTO,
HttpServletRequest request) {
String stationId = Utils.getFrom(request);
log.info("[From: {}] Received stationStatusNotification: {}", stationId, stationStatusDTO);
Lock l = stationLocks.get(stationId);
l.lock();
try {
psiService.handleStationStatusNotification(stationStatusDTO);
} finally {
l.unlock();
}
}
@RequestMapping(value = PEDELEC_STATUS_PATH, method = RequestMethod.POST)
public void pedelecStatusNotification(@RequestBody PedelecStatusDTO pedelecStatusDTO,
HttpServletRequest request) {
String stationId = Utils.getFrom(request);
log.info("[From: {}] Received pedelecStatusNotification: {}", stationId, pedelecStatusDTO);
Lock l = stationLocks.get(stationId);
l.lock();
try {
psiService.handlePedelecStatusNotification(pedelecStatusDTO);
} finally {
l.unlock();
}
}
@RequestMapping(value = CHARGING_STATUS_PATH, method = RequestMethod.POST)
public void chargingStatusNotification(@Valid @RequestBody List<ChargingStatusDTO> chargingStatusDTOs,
HttpServletRequest request) {
String stationId = Utils.getFrom(request);
log.info("[From: {}] Received chargingStatusNotification: {}", stationId, chargingStatusDTOs);
Lock l = stationLocks.get(stationId);
l.lock();
try {
psiService.handleChargingStatusNotification(chargingStatusDTOs);
} finally {
l.unlock();
}
}
@RequestMapping(value = FIRMWARE_STATUS_PATH, method = RequestMethod.POST)
public void firmwareStatusNotification(@RequestBody FirmwareStatusDTO firmwareStatusDTO,
HttpServletRequest request) {
String stationId = Utils.getFrom(request);
log.info("[From: {}] Received firmwareStatusNotification: {}", stationId, firmwareStatusDTO);
// TODO
}
@RequestMapping(value = LOGS_STATUS_PATH, method = RequestMethod.POST)
public void logsStatusNotification(@RequestBody LogsStatusDTO logsStatusDTO,
HttpServletRequest request) {
String stationId = Utils.getFrom(request);
log.info("[From: {}] Received logsStatusNotification: {}", stationId, logsStatusDTO);
// TODO
}
}