Java tutorial
/* * 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.service.business; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; import javax.ejb.Stateless; import javax.inject.Inject; import javax.transaction.Transactional; import javax.transaction.Transactional.TxType; import org.apache.commons.lang.StringUtils; import org.joda.time.LocalDate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import energy.usef.core.config.Config; import energy.usef.core.config.ConfigParam; import energy.usef.core.data.xml.bean.message.CongestionPoint; import energy.usef.core.data.xml.bean.message.PTU; import energy.usef.core.data.xml.bean.message.Prognosis; import energy.usef.core.model.AcknowledgementStatus; import energy.usef.core.model.CongestionPointConnectionGroup; import energy.usef.core.model.Connection; import energy.usef.core.model.ConnectionGroup; import energy.usef.core.model.DocumentStatus; import energy.usef.core.model.DocumentType; import energy.usef.core.model.Exchange; import energy.usef.core.model.PlanboardMessage; import energy.usef.core.model.PtuContainer; import energy.usef.core.model.PtuFlexOffer; import energy.usef.core.model.PtuFlexOrder; import energy.usef.core.model.PtuPrognosis; import energy.usef.core.model.PtuState; import energy.usef.core.repository.CongestionPointConnectionGroupRepository; import energy.usef.core.repository.ConnectionRepository; import energy.usef.core.repository.PlanboardMessageRepository; import energy.usef.core.repository.PtuContainerRepository; import energy.usef.core.repository.PtuFlexOfferRepository; import energy.usef.core.repository.PtuFlexOrderRepository; import energy.usef.core.repository.PtuPrognosisRepository; import energy.usef.core.repository.PtuStateRepository; import energy.usef.core.service.business.SequenceGeneratorService; import energy.usef.core.transformer.PtuListConverter; import energy.usef.core.util.DateTimeUtil; import energy.usef.core.util.DocumentStatusUtil; import energy.usef.core.util.PtuUtil; import energy.usef.core.workflow.dto.FlexOrderDto; import energy.usef.core.workflow.transformer.FlexOrderTransformer; import energy.usef.dso.model.Aggregator; import energy.usef.dso.model.AggregatorOnConnectionGroupState; import energy.usef.dso.model.CommonReferenceOperator; import energy.usef.dso.model.ConnectionCapacityLimitationPeriod; import energy.usef.dso.model.ConnectionMeterEvent; import energy.usef.dso.model.GridSafetyAnalysis; import energy.usef.dso.model.MeterDataCompany; import energy.usef.dso.model.NonAggregatorForecast; import energy.usef.dso.model.PrognosisUpdateDeviation; import energy.usef.dso.model.PtuGridMonitor; import energy.usef.dso.model.SynchronisationCongestionPoint; import energy.usef.dso.model.SynchronisationConnection; import energy.usef.dso.model.SynchronisationConnectionStatusType; import energy.usef.dso.repository.AggregatorOnConnectionGroupStateRepository; import energy.usef.dso.repository.AggregatorRepository; import energy.usef.dso.repository.CommonReferenceOperatorRepository; import energy.usef.dso.repository.ConnectionCapacityLimitationPeriodRepository; import energy.usef.dso.repository.ConnectionMeterEventRepository; import energy.usef.dso.repository.GridSafetyAnalysisRepository; import energy.usef.dso.repository.MeterDataCompanyRepository; import energy.usef.dso.repository.NonAggregatorForecastRepository; import energy.usef.dso.repository.PrognosisUpdateDeviationRepository; import energy.usef.dso.repository.PtuGridMonitorRepository; import energy.usef.dso.repository.SynchronisationCongestionPointRepository; import energy.usef.dso.repository.SynchronisationCongestionPointStatusRepository; import energy.usef.dso.repository.SynchronisationConnectionRepository; import energy.usef.dso.workflow.dto.GridSafetyAnalysisDto; import energy.usef.dso.workflow.transformer.GridSafetyAnalysisDtoTransformer; /** * Service class in charge of operations and validations related to the DSO planboard. */ @Stateless public class DsoPlanboardBusinessService { private static final Logger LOGGER = LoggerFactory.getLogger(DsoPlanboardBusinessService.class); @Inject private Config config; @Inject private AggregatorRepository aggregatorRepository; @Inject private AggregatorOnConnectionGroupStateRepository aggregatorOnConnectionGroupStateRepository; @Inject private CommonReferenceOperatorRepository commonReferenceOperatorRepository; @Inject private CongestionPointConnectionGroupRepository congestionPointConnectionGroupRepository; @Inject private ConnectionMeterEventRepository connectionMeterEventRepository; @Inject private ConnectionCapacityLimitationPeriodRepository connectionCapacityLimitationPeriodRepository; @Inject private ConnectionRepository connectionRepository; @Inject private GridSafetyAnalysisRepository gridSafetyAnalysisRepository; @Inject private MeterDataCompanyRepository meterDataCompanyRepository; @Inject private NonAggregatorForecastRepository nonAggregatorForecastRepository; @Inject private PlanboardMessageRepository planboardMessageRepository; @Inject private PrognosisUpdateDeviationRepository prognosisUpdateDeviationRepository; @Inject private PtuContainerRepository ptuContainerRepository; @Inject private PtuFlexOfferRepository ptuFlexOfferRepository; @Inject private PtuFlexOrderRepository ptuFlexOrderRepository; @Inject private PtuGridMonitorRepository ptuGridMonitorRepository; @Inject private PtuPrognosisRepository ptuPrognosisRepository; @Inject private PtuStateRepository ptuStateRepository; @Inject private SynchronisationCongestionPointRepository synchronisationCongestionPointRepository; @Inject private SynchronisationCongestionPointStatusRepository synchronisationCongestionPointStatusRepository; @Inject private SynchronisationConnectionRepository synchronisationConnectionRepository; @Inject private SequenceGeneratorService sequenceGeneratorService; /** * Gets last NonAggregatorForecasts with current date as start date. * * @param ptuDate ptu date * @return last non aggregator forecasts */ public List<NonAggregatorForecast> findLastNonAggregatorForecasts(LocalDate ptuDate, Optional<String> usefIdentifier) { return nonAggregatorForecastRepository.getLastNonAggregatorForecasts(ptuDate, usefIdentifier); } /** * Gets aggregators by grid point entity adress. * * @param entityAddress grid entity address * @param date the period * @return aggregators */ public List<Aggregator> getAggregatorsByEntityAddress(String entityAddress, LocalDate date) { return aggregatorOnConnectionGroupStateRepository.getAggregatorsByCongestionPointAddress(entityAddress, date); } /** * Counts the {@link AggregatorOnConnectionGroupState}s for this congestionPoint in a moment in time. * * @param entityAddress The congestion Point Entity Address. * @param date The day. * @return aggregators */ public Long countActiveAggregatorsForCongestionPointOnDay(String entityAddress, LocalDate date) { return aggregatorOnConnectionGroupStateRepository .countActiveAggregatorsForCongestionPointOnDay(entityAddress, date); } /** * Find the {@link AggregatorOnConnectionGroupState}s for this congestionPoint in a moment in time. * * @param entityAddress grid entity address * @param date the period * @return aggregators */ public List<AggregatorOnConnectionGroupState> findAggregatorOnConnectionGroupStateByCongestionPointAddress( String entityAddress, LocalDate date) { return aggregatorOnConnectionGroupStateRepository .findAggregatorOnConnectionGroupStateByCongestionPointAddress(entityAddress, date); } /** * Finds the Aggregators on a congestion point. * * @param period {@link LocalDate} period. * @return a {@link Map} with the congestion point as key ({@link CongestionPointConnectionGroup}) and a {@link List} of {@link * AggregatorOnConnectionGroupState} as value. */ public Map<CongestionPointConnectionGroup, List<AggregatorOnConnectionGroupState>> findConnectionGroupsWithAggregators( LocalDate period) { return aggregatorOnConnectionGroupStateRepository.findConnectionGroupsWithAggregators(period); } /** * Finds the {@link AggregatorOnConnectionGroupState} entities with an overlap over the given period. * * @param startDate {@link LocalDate} start date of the period. * @param endDate {@link LocalDate} end date of the period (inclusive). * @return a {@link List} of {@link AggregatorOnConnectionGroupState}. */ public List<AggregatorOnConnectionGroupState> findAggregatorsWithOverlappingActivityForPeriod( LocalDate startDate, LocalDate endDate) { return aggregatorOnConnectionGroupStateRepository.findAggregatorsWithOverlappingActivityForPeriod(startDate, endDate); } /** * Finds the {@link GridSafetyAnalysis} entities for the given parameters with disposition requested for at least one of the * ptu's. * * @param congestionPointEntityAddress {@link String} Entity Address of the related congestion point. * @param ptuDate {@link LocalDate} PTU date (period). * @return a list of {@link GridSafetyAnalysis}. */ public List<GridSafetyAnalysis> findLatestGridSafetyAnalysisWithDispositionRequested( String congestionPointEntityAddress, LocalDate ptuDate) { return gridSafetyAnalysisRepository .findGridSafetyAnalysisWithDispositionRequested(congestionPointEntityAddress, ptuDate); } /** * Finds the grid monitoring data for the given period of time. * * @param startDate {@link LocalDate} start date (inclusive). * @param endDate {@link LocalDate} end date (inclusive). * @return a {@link List} of {@link PtuGridMonitor}. */ public List<PtuGridMonitor> findGridMonitoringData(LocalDate startDate, LocalDate endDate) { return ptuGridMonitorRepository.findPtuGridMonitorsByDates(startDate, endDate); } /** * Create the GridSafetyAnalysisDto Map used in calculations to find optimal flex offer combinations required to place flex * orders. * * @return Map: Congestion point entity address -> Map: PTU Date -> GridSafetyAnalysisDto */ public Map<String, Map<LocalDate, GridSafetyAnalysisDto>> createGridSafetyAnalysisRelatedToFlexOffersDtoMap() { // Map: Congestion point entity address -> Map: PTU Date -> GridSafetyAnalysisDto Map<String, Map<LocalDate, GridSafetyAnalysisDto>> result = new HashMap<>(); List<GridSafetyAnalysis> gsaList = gridSafetyAnalysisRepository .findGridSafetyAnalysisRelatedToFlexOffers(DateTimeUtil.getCurrentDate()); for (GridSafetyAnalysis gsa : gsaList) { // Map: PTU Date -> GridSafetyAnalysisDto Map<LocalDate, GridSafetyAnalysisDto> dateToGridSafetyAnalysisDtoMap = result .get(gsa.getConnectionGroup().getUsefIdentifier()); if (dateToGridSafetyAnalysisDtoMap == null) { dateToGridSafetyAnalysisDtoMap = new HashMap<>(); result.put(gsa.getConnectionGroup().getUsefIdentifier(), dateToGridSafetyAnalysisDtoMap); } GridSafetyAnalysisDto gridSafetyAnalysisDto = dateToGridSafetyAnalysisDtoMap .get(gsa.getPtuContainer().getPtuDate()); if (gridSafetyAnalysisDto == null) { gridSafetyAnalysisDto = new GridSafetyAnalysisDto(); gridSafetyAnalysisDto.setEntityAddress(gsa.getConnectionGroup().getUsefIdentifier()); gridSafetyAnalysisDto.setPtuDate(gsa.getPtuContainer().getPtuDate()); dateToGridSafetyAnalysisDtoMap.put(gsa.getPtuContainer().getPtuDate(), gridSafetyAnalysisDto); } gridSafetyAnalysisDto.getPtus().add(GridSafetyAnalysisDtoTransformer.transform(gsa)); } return result; } /** * Creates flex offers map required to place flex orders. * * @return Map: Congestion point entity address -> Map: PTU Date -> Flex Offer list */ public Map<String, Map<LocalDate, List<PlanboardMessage>>> findOrderableFlexOffers() { List<PlanboardMessage> flexOffers = planboardMessageRepository.findOrderableFlexOffers(); Map<String, List<PlanboardMessage>> flexOffersPerConnectionGroup = flexOffers.stream() .filter(this::validateOffer) .collect(Collectors.groupingBy(pm -> pm.getConnectionGroup().getUsefIdentifier())); return flexOffersPerConnectionGroup.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().stream().collect(Collectors.groupingBy(PlanboardMessage::getPeriod)))); } private boolean validateOffer(PlanboardMessage flexOfferMessage) { if (flexOfferMessage.getExpirationDate().isBefore(DateTimeUtil.getCurrentDateTime())) { flexOfferMessage.setDocumentStatus(DocumentStatus.EXPIRED); LOGGER.info("FlexOffer {} ignored, it expired {}.", flexOfferMessage.getSequence(), flexOfferMessage.getExpirationDate()); return false; } return true; } /** * Find the PTU's for the congestionpoint and period. * * @param period - The Day we want all {@link PtuContainer}'s for. * @return - The Map of {@link PtuContainer}'s mapped by ptu index. */ public Map<Integer, PtuContainer> findPTUContainersForPeriod(LocalDate period) { return ptuContainerRepository.findPtuContainersMap(period); } /** * Find {@link PlanboardMessage} which have status ACCEPTED to know which offers needs to be processed. * * @return the {@link PlanboardMessage} with status ACCEPTED. */ public List<PlanboardMessage> findNewOffers() { return planboardMessageRepository.findPlanboardMessages(DocumentType.FLEX_OFFER, DocumentStatus.ACCEPTED); } /** * Updates flexibility orders with acknowledgement status. * * @param sequence sequence number * @param acknowledgementStatus acknowledgement status * @param aggregatorDomain aggregator domain * @return flex order DTO containing the whole data set corresponding to the updated flex orders. In case there was found no * flex order to update the flex order DTO has empty properties */ public FlexOrderDto updateFlexOrdersWithAcknowledgementStatus(Long sequence, final AcknowledgementStatus acknowledgementStatus, String aggregatorDomain) { PlanboardMessage flexOrderMessage = planboardMessageRepository.findSinglePlanboardMessage(sequence, DocumentType.FLEX_ORDER, aggregatorDomain); if (!DocumentStatus.SENT.equals(flexOrderMessage.getDocumentStatus())) { LOGGER.error("A response has already been processed for this flex order %s. Invalid response received " + "from %s. ", sequence, aggregatorDomain); return null; } flexOrderMessage.setDocumentStatus(DocumentStatusUtil.toDocumentStatus(acknowledgementStatus)); List<PtuFlexOrder> flexOrders = ptuFlexOrderRepository.findFlexOrdersBySequence(sequence); List<PtuFlexOrder> changedFlexOrders = new ArrayList<>(); flexOrders.stream() .filter(flexOrder -> AcknowledgementStatus.SENT.equals(flexOrder.getAcknowledgementStatus()) || AcknowledgementStatus.NO_RESPONSE.equals(flexOrder.getAcknowledgementStatus())) .forEach(flexOrder -> { changedFlexOrders.add(flexOrder); flexOrder.setAcknowledgementStatus(acknowledgementStatus); }); return FlexOrderTransformer.transformPtuFlexOrders(changedFlexOrders); } /** * Handles the business logic related to the receipt of an updated version of a prognosis. * * @param prognosis {@link Prognosis} message. * @param existingPtuPrognoses {@link List} of {@link PtuPrognosis}, which is a list of all existing d-prognosis for a * congestion point on a specific period. */ public void handleUpdatedPrognosis(Prognosis prognosis, List<PtuPrognosis> existingPtuPrognoses) { String aggregatorDomain = prognosis.getMessageMetadata().getSenderDomain(); Long latestPrognosisSequence = getDocumentLatestSequenceNumber(existingPtuPrognoses, aggregatorDomain); // 1. Find the flex order messages related to the updated prognosis. List<PlanboardMessage> planboardFlexOrders = planboardMessageRepository .findFlexOrdersRelatedToPrognosis(latestPrognosisSequence, aggregatorDomain); LOGGER.info("Found {} related flex orders for the prognosis with sequence {}.", planboardFlexOrders.size(), latestPrognosisSequence); // 2. Find all the PTU Flex Orders for each FlexOrder message. List<PtuFlexOrder> ptuFlexOrders = new ArrayList<>(); for (PlanboardMessage planboardFlexOrder : planboardFlexOrders) { ptuFlexOrders.addAll(ptuFlexOrderRepository.findFlexOrdersBySequence(planboardFlexOrder.getSequence())); } // 3.1. If there are no flex orders at the moment, log it and persist the updated prognosis. if (ptuFlexOrders.isEmpty()) { LOGGER.info("No orders have been placed. Updated prognosis has no impact."); } else { // 3.2. If there are existing flex orders. // 3.2.1. Create a map of PTUIndex / List of flex orders for the ptu. Map<Integer, List<PtuFlexOrder>> ptuFlexOrdersMap = sortAndMapPtuFlexOrders(ptuFlexOrders); for (PTU ptu : PtuListConverter.normalize(prognosis.getPTU())) { // 3.2.2. For each ptu, sum the flex ordered. BigInteger power = sumPowerOfFlexOrders(ptuFlexOrdersMap.get(ptu.getStart().intValue())); PtuPrognosis previousPtuPrognosis = fetchPreviousPtuPrognosis(existingPtuPrognoses, aggregatorDomain, ptu.getStart().intValue()); /* * 3.2.3. If there is a gap between the difference between previous prognosed power and order flex, and with the * updated prognosed power, record the fact in the database. */ if (!(previousPtuPrognosis.getPower().add(power)).equals(ptu.getPower())) { LOGGER.warn( "Sum of the flex ordered summed to previous prognosis power does not match updated prognosed power " + "for the PTU with index {} on {} for prognosis {})!", ptu.getStart().intValue(), prognosis.getPeriod(), prognosis.getSequence()); prognosisUpdateDeviationRepository.persist(new PrognosisUpdateDeviation(prognosis.getSequence(), aggregatorDomain, prognosis.getPeriod().toDateMidnight().toDate(), ptu.getStart().intValue(), power, previousPtuPrognosis.getPower(), ptu.getPower())); } } } } /** * Gets the latest sequence number in a list of {@link Exchange}. * * @param exchanges {@link List} of {@link Exchange}. * @param participantDomain {@link String} domain name of the correspondent participant. * @return a {@link Long} with the highest sequence number; */ private Long getDocumentLatestSequenceNumber(List<? extends Exchange> exchanges, String participantDomain) { Long result = -1L; for (Exchange exchange : exchanges) { if (participantDomain.equals(exchange.getParticipantDomain())) { continue; } if (result.compareTo(exchange.getSequence()) == -1) { result = exchange.getSequence(); } } return result; } /** * Maps a list of {@link PtuFlexOrder} with their PTU index. * * @param ptuFlexOrders {@link List} of {@link PtuFlexOrder}. * @return a mapping between the PTU index and the list of {@link PtuFlexOrder} for this very PTU index. */ private Map<Integer, List<PtuFlexOrder>> sortAndMapPtuFlexOrders(List<PtuFlexOrder> ptuFlexOrders) { Map<Integer, List<PtuFlexOrder>> result = new HashMap<>(); Integer ptuIndex; for (PtuFlexOrder ptuFlexOrder : ptuFlexOrders) { ptuIndex = ptuFlexOrder.getPtuContainer().getPtuIndex(); if (result.get(ptuIndex) == null) { result.put(ptuIndex, new ArrayList<>(Collections.singletonList(ptuFlexOrder))); } else { result.get(ptuIndex).add(ptuFlexOrder); } } return result; } /** * Sums the power of the Flex Orders. * * @param ptuFlexOrders {@link List} of {@link PtuFlexOrder}. * @return the sum of the power. */ private BigInteger sumPowerOfFlexOrders(List<PtuFlexOrder> ptuFlexOrders) { BigInteger result = BigInteger.ZERO; for (PtuFlexOrder ptuFlexOrder : ptuFlexOrders) { if (AcknowledgementStatus.ACCEPTED != ptuFlexOrder.getAcknowledgementStatus()) { continue; } PtuFlexOffer ptuFlexOffer = getRelatedPtuFlexOffer(ptuFlexOrder); result = result.add(ptuFlexOffer.getPower()); } return result; } /** * Gets the flex offer related to a flex order on a given PTU. * * @param ptuFlexOrder {@link PtuFlexOrder}. * @return a {@link PtuFlexOffer} or <code>null</code>. */ private PtuFlexOffer getRelatedPtuFlexOffer(PtuFlexOrder ptuFlexOrder) { return ptuFlexOfferRepository.findPtuFlexOfferWithSequence(ptuFlexOrder.getFlexOfferSequence(), ptuFlexOrder.getParticipantDomain(), ptuFlexOrder.getPtuContainer().getPtuIndex()); } /** * In the list of all previous prognoses for all aggregators, this method fetches the one for a given aggregator and a given ptu * index. * * @param lastPtuPrognoses {@link List} of previous {@link PtuPrognosis}. * @param aggregatorDomain {@link String} domain name of the aggregator. * @param ptuIndex {@link Integer} index of the PTU. * @return a {@link PtuPrognosis} or <code>null</code>. */ private PtuPrognosis fetchPreviousPtuPrognosis(List<PtuPrognosis> lastPtuPrognoses, String aggregatorDomain, Integer ptuIndex) { for (PtuPrognosis prognosis : lastPtuPrognoses) { if (aggregatorDomain.equals(prognosis.getParticipantDomain()) && ptuIndex.equals(prognosis.getPtuContainer().getPtuIndex())) { return prognosis; } } return null; } /** * Saves Non Aggregator Connection Forecast. * * @param congestionPointConnectionGroup the {@link CongestionPointConnectionGroup} of the forecast * @param ptuDate PTU date * @param power power array * @param maxload max load array */ public void saveNonAggregatorConnectionForecast(CongestionPointConnectionGroup congestionPointConnectionGroup, LocalDate ptuDate, List<Long> power, List<Long> maxload) { int length = power.size(); if (length == 0) { int ptuDuration = config.getIntegerProperty(ConfigParam.PTU_DURATION); length = PtuUtil.getNumberOfPtusPerDay(ptuDate, ptuDuration); } Map<Integer, PtuContainer> ptuContainers = ptuContainerRepository.findPtuContainersMap(ptuDate); for (int i = 0; i < length; i++) { Integer ptuIndex = i + 1; PtuContainer ptuContainer = ptuContainers.get(ptuIndex); if (ptuContainer == null) { ptuContainer = new PtuContainer(ptuDate, ptuIndex); ptuContainerRepository.persist(ptuContainer); LOGGER.trace("Persisted ptuContainer"); } else { LOGGER.trace("Existing ptuContainer"); } if (i < power.size()) { LOGGER.trace("Persisted nonAggregatorForecast"); NonAggregatorForecast nonAggregatorForecast = new NonAggregatorForecast(); nonAggregatorForecast.setMaxLoad(maxload.get(i)); nonAggregatorForecast.setPower(power.get(i)); nonAggregatorForecast.setSequence(sequenceGeneratorService.next()); nonAggregatorForecast.setPtuContainer(ptuContainer); nonAggregatorForecast.setConnectionGroup(congestionPointConnectionGroup); nonAggregatorForecast.setCreationDate(ptuDate.toDateMidnight().toDate()); nonAggregatorForecastRepository.persist(nonAggregatorForecast); } } LOGGER.info("Forecast saved {} PTU's, length = {}", power.size(), length); } /** * Finds all {@link CommonReferenceOperator}s and {@link SynchronisationConnection}s and put them in a Map, all {@link * SynchronisationConnection}s are send to all {@link CommonReferenceOperator}s. * * @return Map with CRO domain mapped to {@link List} of {@link SynchronisationCongestionPoint} objects. */ public Map<String, List<SynchronisationCongestionPoint>> findConnectionsPerCRO() { List<SynchronisationCongestionPoint> congestionPoints = synchronisationCongestionPointRepository.findAll(); List<CommonReferenceOperator> cros = commonReferenceOperatorRepository.findAll(); Map<String, List<SynchronisationCongestionPoint>> congestionPointsPerCRO = new HashMap<>(); if (congestionPoints.isEmpty() || cros.isEmpty()) { return congestionPointsPerCRO; } for (CommonReferenceOperator cro : cros) { congestionPointsPerCRO.put(cro.getDomain(), congestionPoints); } return congestionPointsPerCRO; } /** * Updates all CongestionPoints where the synchronisationTime is > as the lastModificationTime for this croDomain. * * @param congestionPointEntityAddress the entity address ({@link String}) of the congestion point * @param croDomain the domain name ({@link String}) of the CRO */ @Transactional(value = TxType.REQUIRES_NEW) public void updateCongestionPointStatusForCRO(String congestionPointEntityAddress, String croDomain) { synchronisationCongestionPointRepository.updateCongestionPointStatusForCRO(congestionPointEntityAddress, croDomain); } /** * Clean's the synchronization table's if synchronization is complete. */ public void cleanSynchronization() { long countModified = synchronisationCongestionPointStatusRepository .countSynchronisationConnectionStatusWithStatus(SynchronisationConnectionStatusType.MODIFIED); long countDeleted = synchronisationCongestionPointStatusRepository .countSynchronisationConnectionStatusWithStatus(SynchronisationConnectionStatusType.DELETED); if (countModified + countDeleted == 0L) { // everything is synchronized, time to remove everything. synchronisationCongestionPointStatusRepository.deleteAll(); synchronisationConnectionRepository.deleteAll(); synchronisationCongestionPointRepository.deleteAll(); } } /** * Updates the aggregaters linked to the congestionPoint. * * @param xmlCongestionPoint {@link CongestionPoint} for which the aggregator count will be updated. * @param initializationDate {@link LocalDate} date of the initializtion of the aggregator count. * @param initializationDuration {@link Integer} duration of the initalization. */ public void updateAggregatorsOnCongestionPointConnectionGroup(CongestionPoint xmlCongestionPoint, LocalDate initializationDate, Integer initializationDuration) { CongestionPointConnectionGroup congestionPoint = congestionPointConnectionGroupRepository .findOrCreate(xmlCongestionPoint.getEntityAddress(), config.getProperty(ConfigParam.HOST_DOMAIN)); List<AggregatorOnConnectionGroupState> endingAtDate = aggregatorOnConnectionGroupStateRepository .findEndingAggregatorOnConnectionGroupStates(congestionPoint.getUsefIdentifier(), initializationDate); // for each ending aggregator/connection group state for which nothing is updated, extend the valid until date. endingAtDate.stream() .filter(aocgs -> xmlCongestionPoint.getAggregator().stream() .anyMatch(aggregator -> aocgs.getConnectionCount().equals(aggregator.getConnectionCount()) && aocgs.getAggregator().getDomain().equals(aggregator.getDomain()) && aocgs.getCongestionPointConnectionGroup().getUsefIdentifier() .equals(xmlCongestionPoint.getEntityAddress()))) .forEach(aocgs -> aocgs.setValidUntil(aocgs.getValidUntil().plusDays(initializationDuration))); // create new records if anything changed xmlCongestionPoint.getAggregator().stream() .filter(aggregator -> endingAtDate.stream() .noneMatch(aocgs -> aocgs.getConnectionCount().equals(aggregator.getConnectionCount()) && aocgs.getAggregator().getDomain().equals(aggregator.getDomain()) && aocgs.getCongestionPointConnectionGroup().getUsefIdentifier() .equals(xmlCongestionPoint.getEntityAddress()))) .filter(xmlAggregator -> StringUtils.isNotEmpty(xmlAggregator.getDomain())) .forEach(xmlAggregator -> { Aggregator dbAggregator = aggregatorRepository.findOrCreate(xmlAggregator.getDomain()); AggregatorOnConnectionGroupState newState = new AggregatorOnConnectionGroupState(); newState.setAggregator(dbAggregator); newState.setConnectionCount(xmlAggregator.getConnectionCount() == null ? BigInteger.ZERO : xmlAggregator.getConnectionCount()); newState.setValidFrom(initializationDate); newState.setValidUntil(initializationDate.plusDays(initializationDuration)); newState.setCongestionPointConnectionGroup(congestionPoint); aggregatorOnConnectionGroupStateRepository.persist(newState); }); } /** * Gets last NonAggregatorForecast. */ public NonAggregatorForecast getLastNonAggregatorForecast() { return nonAggregatorForecastRepository.getLastNonAggregatorForecast(); } /** * Return a list of all MeterDataCompany entities. * * @return List of MeterDataCompany entities */ public List<MeterDataCompany> findAllMDCs() { return meterDataCompanyRepository.findAll(); } /** * Finds the current connection count for a specified usef identifier. * * @param usefIdentifier {@link String} usef identifier. * @return a {@link Long}. */ public Long findConnectionCountByUsefIdentifier(String usefIdentifier) { return connectionRepository.findConnectionCountByUsefIdentifier(usefIdentifier, DateTimeUtil.getCurrentDate()); } /** * Finds a PTU state and create if it does not exist. * * @param ptuContainer PTU Container * @param connectionGroup Connection Group * @return PtuState */ @SuppressWarnings("unchecked") public PtuState findOrCreatePtuState(PtuContainer ptuContainer, ConnectionGroup connectionGroup) { return ptuStateRepository.findOrCreatePtuState(ptuContainer, connectionGroup); } /** * Retreive the limited power at this PTU. * * @param ptuContainer {@link PtuContainer} the specified PTU (not nullable). * @param connectionGroup {@link ConnectionGroup} a congestion point (not nullable). * @return an {@link Optional} of {@link Long} limited power for the given PTU and the given congestion point. */ public Optional<Long> findLimitedPower(PtuContainer ptuContainer, ConnectionGroup connectionGroup) { return ptuGridMonitorRepository.findLimitedPower(ptuContainer, connectionGroup); } /** * Store the limited power at this PTU. * * @param ptuContainer * @param limitedPower * @param connectionGroup */ public void setLimitedPower(PtuContainer ptuContainer, Long limitedPower, ConnectionGroup connectionGroup) { ptuGridMonitorRepository.setLimitedPower(ptuContainer, limitedPower, connectionGroup); } /** * Store the actual power at this PTU. If the power already exists, store the median of the current and the new value instead. * * @param ptuContainer * @param actualPower * @param connectionGroup */ @SuppressWarnings("unchecked") public void setActualPower(PtuContainer ptuContainer, Long actualPower, ConnectionGroup connectionGroup) { ptuGridMonitorRepository.setActualPower(ptuContainer, actualPower, connectionGroup); } /** * Finds {@link PtuContainer} entity for given period and a given index. This method should only be called in a OPERATE context * and not in a loop. If in a loop, use {@link PtuContainerRepository#findPtuContainersMap(LocalDate)}; * * @param period {@link LocalDate} period. * @param ptuIndex {@link Integer} The Ptu Index. * @return a {@link PtuContainer}. */ public PtuContainer findPtuContainer(LocalDate period, Integer ptuIndex) { return ptuContainerRepository.findPtuContainer(period, ptuIndex); } /** * Finds all {@link CongestionPointConnectionGroup} active for the specific time. * * @param date date time * @return {@link CongestionPointConnectionGroup} list */ public List<CongestionPointConnectionGroup> findActiveCongestionPointConnectionGroup(LocalDate date) { return congestionPointConnectionGroupRepository.findActiveCongestionPointConnectionGroup(date); } /** * Gets the entire list of {@link CommonReferenceOperator} known by this Balance Responsible Party. * * @return {@link List} of {@link CommonReferenceOperator} */ @SuppressWarnings("unchecked") public List<CommonReferenceOperator> findAllCommonReferenceOperators() { return commonReferenceOperatorRepository.findAll(); } /** * This method finds a Connection for a given connection entity address and a certain period. * * @param entityAddress connection entity address * @param date date * @return connection if exists, null otherwise */ @SuppressWarnings("unchecked") public Connection findConnectionForConnectionMeterEventsPeriod(String entityAddress, LocalDate date) { return connectionMeterEventRepository.findConnectionForConnectionMeterEventsPeriod(entityAddress, date); } /** * Store a {@Link ConnectionMeterEvent}. * * @param entity Connection Meter Event */ public void storeConnectionMeterEvent(ConnectionMeterEvent entity) { connectionMeterEventRepository.persist(entity); } /** * Finds connections not related to ConnectionMeterEvents. * * @param date date * @param connectionIncludeList connection include list * @return connection list */ public List<Connection> findConnectionsNotRelatedToConnectionMeterEvents(LocalDate date, List<String> connectionIncludeList) { return connectionMeterEventRepository.findConnectionsNotRelatedToConnectionMeterEvents(date, connectionIncludeList); } /** * This method finds all ConnectionMeterEvents for a certain period that where active in that period. * * @param fromDate from date * @param endDate end date * * @return connection meter event list */ @SuppressWarnings("unchecked") public List<ConnectionMeterEvent> findConnectionMeterEventsForPeriod(LocalDate fromDate, LocalDate endDate) { return connectionMeterEventRepository.findConnectionMeterEventsForPeriod(fromDate, endDate); } /** * Store a {@Link ConnectionCapacityLimitationPeriod}. * * @param entity Connection Capacity Limitation Period */ public void storeConnectionMeterEventPeriod(ConnectionCapacityLimitationPeriod entity) { connectionCapacityLimitationPeriodRepository.persist(entity); } /** * Get Aggregators by CongestionPointAddress. * * @param congestionPointAddress {@link String} entity address of the congestion point. * @param dateTime {@link org.joda.time.LocalDateTime} validity moment of the {@link AggregatorOnConnectionGroupState}. * @return list of {@link Aggregator}. */ public List<Aggregator> getAggregatorsByCongestionPointAddress(String congestionPointAddress, LocalDate dateTime) { return aggregatorOnConnectionGroupStateRepository .getAggregatorsByCongestionPointAddress(congestionPointAddress, dateTime); } /** * Store a {@Link GridSafetyAnalysis}. * * @param entity Grid Safety Analysis */ public void storeGridSafetyAnalysis(GridSafetyAnalysis entity) { gridSafetyAnalysisRepository.persist(entity); } /** * Finds the {@link GridSafetyAnalysis} entities for a given day. * * @param congestionPointEntityAddress {@link String} related Congestion Point entity address. * @param ptuDate {@link LocalDate} Period of the PTU. * @return a {@link List} of {@link GridSafetyAnalysis}. */ @SuppressWarnings("unchecked") public List<GridSafetyAnalysis> findGridSafetyAnalysis(String congestionPointEntityAddress, LocalDate ptuDate) { return gridSafetyAnalysisRepository.findGridSafetyAnalysis(congestionPointEntityAddress, ptuDate); } /** * Deletes the {@link GridSafetyAnalysis} entities for a given day and congestion point. * * @param entityAddress {@link String} related Congestion Point entity address. * @param period {@link LocalDate} Period of the PTU. */ @SuppressWarnings("unchecked") public int deletePreviousGridSafetyAnalysis(String entityAddress, LocalDate period) { return gridSafetyAnalysisRepository.deletePreviousGridSafetyAnalysis(entityAddress, period); } }