energy.usef.dso.workflow.settlement.send.DsoSendSettlementMessagesCoordinator.java Source code

Java tutorial

Introduction

Here is the source code for energy.usef.dso.workflow.settlement.send.DsoSendSettlementMessagesCoordinator.java

Source

/*
 * Copyright 2015-2016 USEF Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package energy.usef.dso.workflow.settlement.send;

import static energy.usef.core.data.xml.bean.message.MessagePrecedence.TRANSACTIONAL;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.ejb.Asynchronous;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Singleton;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.enterprise.event.Event;
import javax.enterprise.event.Observes;
import javax.enterprise.event.TransactionPhase;
import javax.inject.Inject;

import org.joda.time.LocalDate;
import org.joda.time.Months;
import org.joda.time.Period;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import energy.usef.core.config.Config;
import energy.usef.core.config.ConfigParam;
import energy.usef.core.constant.USEFConstants;
import energy.usef.core.data.xml.bean.message.FlexOrderSettlement;
import energy.usef.core.data.xml.bean.message.MessageMetadata;
import energy.usef.core.data.xml.bean.message.PTUSettlement;
import energy.usef.core.data.xml.bean.message.SettlementMessage;
import energy.usef.core.data.xml.bean.message.USEFRole;
import energy.usef.core.model.DocumentStatus;
import energy.usef.core.model.DocumentType;
import energy.usef.core.service.business.CorePlanboardBusinessService;
import energy.usef.core.service.business.SequenceGeneratorService;
import energy.usef.core.service.helper.JMSHelperService;
import energy.usef.core.service.helper.MessageMetadataBuilder;
import energy.usef.core.util.XMLUtil;
import energy.usef.core.workflow.settlement.CoreSettlementBusinessService;
import energy.usef.core.workflow.transformer.SettlementTransformer;
import energy.usef.dso.config.ConfigDso;
import energy.usef.dso.config.ConfigDsoParam;
import energy.usef.dso.model.Aggregator;
import energy.usef.dso.model.AggregatorOnConnectionGroupState;
import energy.usef.dso.service.business.DsoDefaultSettlementMessageContent;
import energy.usef.dso.service.business.DsoPlanboardBusinessService;

/**
 * This coordinator class is in charge of the workflow sending Settlement messages to aggregators.
 */
@Singleton
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class DsoSendSettlementMessagesCoordinator {

    private static final Logger LOGGER = LoggerFactory.getLogger(DsoSendSettlementMessagesCoordinator.class);

    @Inject
    private Config config;
    @Inject
    private ConfigDso configDso;
    @Inject
    private JMSHelperService jmsHelperService;
    @Inject
    private DsoPlanboardBusinessService dsoPlanboardBusinessService;
    @Inject
    private CorePlanboardBusinessService corePlanboardBusinessService;
    @Inject
    private CoreSettlementBusinessService coreSettlementBusinessService;
    @Inject
    private SequenceGeneratorService sequenceGeneratorService;
    @Inject
    private Event<SendSettlementMessageEvent> sendSettlementMessageEventManager;

    @Asynchronous
    @Lock(LockType.WRITE)
    public void isReadyToSendSettlementMessage(
            @Observes(during = TransactionPhase.AFTER_COMPLETION) CheckInitiateSettlementDoneEvent event) {
        LOGGER.debug(USEFConstants.LOG_COORDINATOR_START_HANDLING_EVENT, event);

        LocalDate period = new LocalDate(event.getYear(), event.getMonth(), 1);
        boolean isNotProcessed = corePlanboardBusinessService.findPlanboardMessages(
                DocumentType.FLEX_ORDER_SETTLEMENT, period, period.plusMonths(1).minusDays(1), null).size() == 0;
        if (isNotProcessed && coreSettlementBusinessService.isEachFlexOrderReadyForSettlement(event.getYear(),
                event.getMonth())) {
            sendSettlementMessageEventManager
                    .fire(new SendSettlementMessageEvent(event.getYear(), event.getMonth()));
        }
        LOGGER.debug(USEFConstants.LOG_COORDINATOR_FINISHED_HANDLING_EVENT, event);
    }

    /**
     * This method starts the workflow when triggered by an event.
     *
     * @param event {@link SendSettlementMessageEvent} event which starts the workflow.
     */
    public void invokeWorkflow(@Observes SendSettlementMessageEvent event) {
        LOGGER.debug(USEFConstants.LOG_COORDINATOR_START_HANDLING_EVENT, event);

        LocalDate dateFrom = new LocalDate(event.getYear(), event.getMonth(), 1);
        LocalDate dateUntil = dateFrom.plus(Months.ONE).minusDays(1);

        // Fetch all aggregators having ptusettlement in the period defined by [dateFrom, dateUntil].
        List<String> aggregators = dsoPlanboardBusinessService
                .findAggregatorsWithOverlappingActivityForPeriod(dateFrom, dateUntil).stream()
                .map(AggregatorOnConnectionGroupState::getAggregator).map(Aggregator::getDomain).distinct()
                .collect(Collectors.toList());

        // Fetch all FlexOrderSettlement for the period
        Map<String, List<energy.usef.core.model.FlexOrderSettlement>> flexOrderSettlementPerAggregator = coreSettlementBusinessService
                .findFlexOrderSettlementsForPeriod(dateFrom, dateUntil, Optional.empty(), Optional.empty()).stream()
                .collect(Collectors.groupingBy(
                        flexOrderSettlement -> flexOrderSettlement.getFlexOrder().getParticipantDomain()));

        for (String aggregator : aggregators) {
            SettlementMessage settlementMessage = buildSettlementMessage(
                    flexOrderSettlementPerAggregator.get(aggregator), dateFrom);
            populateSettlementMessageData(settlementMessage, aggregator, dateFrom, dateUntil);
            storeSettlementMessage(aggregator, flexOrderSettlementPerAggregator.get(aggregator));
            jmsHelperService.sendMessageToOutQueue(XMLUtil.messageObjectToXml(settlementMessage));
        }
        LOGGER.debug(USEFConstants.LOG_COORDINATOR_FINISHED_HANDLING_EVENT, event);
    }

    private SettlementMessage buildSettlementMessage(
            List<energy.usef.core.model.FlexOrderSettlement> flexOrderSettlements, LocalDate dateFrom) {
        if (flexOrderSettlements == null || flexOrderSettlements.isEmpty()) {
            return buildDefaultSettlementMessage(dateFrom);
        }
        SettlementMessage settlementMessage = new SettlementMessage();
        for (energy.usef.core.model.FlexOrderSettlement flexOrderSettlement : flexOrderSettlements) {
            settlementMessage.getFlexOrderSettlement()
                    .add(SettlementTransformer.transformToXml(flexOrderSettlement));
        }
        return settlementMessage;
    }

    private void populateSettlementMessageData(SettlementMessage settlementMessage, String aggregatorDomain,
            LocalDate dateFrom, LocalDate dateUntil) {
        MessageMetadata messageMetadata = new MessageMetadataBuilder().conversationID().messageID().timeStamp()
                .senderDomain(config.getProperty(ConfigParam.HOST_DOMAIN)).senderRole(USEFRole.DSO)
                .recipientDomain(aggregatorDomain).recipientRole(USEFRole.AGR).precedence(TRANSACTIONAL).build();
        settlementMessage.setMessageMetadata(messageMetadata);
        settlementMessage.setCurrency(config.getProperty(ConfigParam.CURRENCY));
        settlementMessage.setPeriodStart(dateFrom);
        settlementMessage.setPeriodEnd(dateUntil);
        settlementMessage.setPTUDuration(Period.minutes(config.getIntegerProperty(ConfigParam.PTU_DURATION)));
        settlementMessage.setTimeZone(config.getProperty(ConfigParam.TIME_ZONE));
        settlementMessage
                .setReference(config.getProperty(ConfigParam.HOST_DOMAIN) + sequenceGeneratorService.next());
    }

    private void storeSettlementMessage(String aggregatorDomain,
            List<energy.usef.core.model.FlexOrderSettlement> flexOrderSettlements) {
        corePlanboardBusinessService.storeFlexOrderSettlementsPlanboardMessage(flexOrderSettlements,
                configDso.getIntegerProperty(ConfigDsoParam.DSO_SETTLEMENT_RESPONSE_WAITING_DURATION),
                DocumentStatus.SENT, aggregatorDomain, null);
    }

    private SettlementMessage buildDefaultSettlementMessage(LocalDate dateFrom) {
        SettlementMessage settlementMessage = new SettlementMessage();

        FlexOrderSettlement defaultFlexOrderSettlement = new FlexOrderSettlement();
        defaultFlexOrderSettlement.setPeriod(dateFrom);
        defaultFlexOrderSettlement
                .setOrderReference(DsoDefaultSettlementMessageContent.ORDER_SETTLEMENT_ORDER_REFERENCE.getValue());
        settlementMessage.getFlexOrderSettlement().add(defaultFlexOrderSettlement);

        PTUSettlement defaultPtuSettlement = new PTUSettlement();
        defaultPtuSettlement.setActualPower(
                new BigInteger(DsoDefaultSettlementMessageContent.PTU_SETTLEMENT_ACTUAL_POWER.getValue()));
        defaultPtuSettlement.setDeliveredFlexPower(
                new BigInteger(DsoDefaultSettlementMessageContent.PTU_SETTLEMENT_DELIVERED_FLEX_POWER.getValue()));
        defaultPtuSettlement.setNetSettlement(
                new BigDecimal(DsoDefaultSettlementMessageContent.PTU_SETTLEMENT_NET_SETTLEMENT.getValue()));
        defaultPtuSettlement.setOrderedFlexPower(
                new BigInteger(DsoDefaultSettlementMessageContent.PTU_SETTLEMENT_ORDERED_FLEX_POWER.getValue()));
        defaultPtuSettlement.setPrognosisPower(
                new BigInteger(DsoDefaultSettlementMessageContent.PTU_SETTLEMENT_PROGNOSIS_POWER.getValue()));
        defaultPtuSettlement
                .setPrice(new BigDecimal(DsoDefaultSettlementMessageContent.PTU_SETTLEMENT_PRICE.getValue()));
        defaultPtuSettlement
                .setStart(new BigInteger(DsoDefaultSettlementMessageContent.PTU_SETTLEMENT_START.getValue()));
        defaultFlexOrderSettlement.getPTUSettlement().add(defaultPtuSettlement);

        return settlementMessage;
    }
}