package de.rwth.idsg.steve.ocpp.soap;
import de.rwth.idsg.steve.ocpp.OcppProtocol;
import de.rwth.idsg.steve.repository.OcppServerRepository;
import de.rwth.idsg.steve.repository.impl.ChargePointRepositoryImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.message.Message;
import org.apache.cxf.message.MessageContentsList;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.apache.cxf.service.model.MessageInfo;
import org.apache.cxf.service.model.MessagePartInfo;
import org.apache.cxf.ws.addressing.AddressingProperties;
import org.apache.cxf.ws.addressing.ContextUtils;
import org.apache.cxf.ws.addressing.EndpointReferenceType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.concurrent.ScheduledExecutorService;
import static org.apache.cxf.ws.addressing.JAXWSAConstants.ADDRESSING_PROPERTIES_INBOUND;
/**
* Intercepts incoming OCPP messages to update the endpoint address ("From" field of the WS-A header) in DB.
* And the absence of the field is not a deal breaker anymore. But, as a side effect, the user will not be able
* to send commands to the charging station, since the DB call to list the charge points will filter it out. See
* {@link ChargePointRepositoryImpl#getChargePointSelect(OcppProtocol)}.
*
* @author Sevket Goekay <goekay@dbis.rwth-aachen.de>
* @since 15.06.2015
*/
@Slf4j
@Component("FromAddressInterceptor")
public class FromAddressInterceptor extends AbstractPhaseInterceptor<Message> {
@Autowired private OcppServerRepository ocppServerRepository;
@Autowired private ScheduledExecutorService executorService;
private static final String CHARGEBOX_ID_HEADER = "ChargeBoxIdentity";
public FromAddressInterceptor() {
super(Phase.PRE_INVOKE);
}
@Override
public void handleMessage(Message message) throws Fault {
executorService.execute(() -> handleMessageInternal(message));
}
private void handleMessageInternal(Message message) {
try {
String chargeBoxId = getChargeBoxId(message);
String endpointAddress = getEndpointAddress(message);
if (chargeBoxId != null && endpointAddress != null) {
ocppServerRepository.updateEndpointAddress(chargeBoxId, endpointAddress);
}
} catch (Exception e) {
log.error("Exception occurred", e);
}
}
private String getChargeBoxId(Message message) {
MessageContentsList lst = MessageContentsList.getContentsList(message);
if (lst == null) {
return null;
}
MessageInfo mi = (MessageInfo) message.get("org.apache.cxf.service.model.MessageInfo");
for (MessagePartInfo mpi : mi.getMessageParts()) {
if (CHARGEBOX_ID_HEADER.equals(mpi.getName().getLocalPart())) {
return (String) lst.get(mpi);
}
}
return null;
}
private String getEndpointAddress(Message message) {
AddressingProperties addressProp = (AddressingProperties) message.get(ADDRESSING_PROPERTIES_INBOUND);
if (addressProp == null) {
return null;
}
EndpointReferenceType from = addressProp.getFrom();
if (ContextUtils.isGenericAddress(from)) {
return null;
} else {
return from.getAddress().getValue();
}
}
}