GovernmentBodyDataLoaderServiceImpl.java
/*
* Copyright 2010-2025 James Pether Sörling
*
* 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.
*
* $Id$
* $HeadURL$
*/
package com.hack23.cia.service.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import com.hack23.cia.model.internal.application.data.ministry.impl.GovernmentBodyData;
import com.hack23.cia.service.data.api.GovernmentBodyDataDAO;
import com.hack23.cia.service.external.esv.api.EsvApi;
import com.hack23.cia.service.external.esv.api.GovernmentBodyAnnualSummary;
/**
* The Class GovernmentBodyDataLoaderServiceImpl.
* Loads government body data from ESV at application startup if not already loaded.
*/
@Component
public final class GovernmentBodyDataLoaderServiceImpl implements GovernmentBodyDataLoaderService {
private static final Logger LOGGER = LoggerFactory.getLogger(GovernmentBodyDataLoaderServiceImpl.class);
@Autowired
private GovernmentBodyDataDAO governmentBodyDataDAO;
@Autowired
private EsvApi esvApi;
/**
* Instantiates a new government body data loader service impl.
*/
public GovernmentBodyDataLoaderServiceImpl() {
super();
}
/**
* Load government body data at startup if table is empty.
* Uses EventListener with ContextRefreshedEvent to ensure transaction manager is fully initialized.
*
* @param event the context refreshed event
*/
@Override
@EventListener
@Transactional
public void loadGovernmentBodyDataIfEmpty(final ContextRefreshedEvent event) {
try {
configureAuthentication("ROLE_ADMIN");
final List<GovernmentBodyData> existingData = governmentBodyDataDAO.getAll();
if (existingData == null || existingData.isEmpty()) {
LOGGER.info("Government body data table is empty, loading data from ESV...");
loadDataFromEsv();
LOGGER.info("Government body data loaded successfully");
} else {
LOGGER.info("Government body data already exists ({} records), skipping load", existingData.size());
}
} catch (final Exception e) {
LOGGER.error("Failed to load government body data - application startup aborted", e);
throw new RuntimeException("Failed to initialize government body data", e);
} finally {
clearAuthentication();
}
}
/**
* Load data from ESV API using batch processing for efficiency.
*/
private void loadDataFromEsv() {
final Map<Integer, List<GovernmentBodyAnnualSummary>> data = esvApi.getData();
final List<GovernmentBodyData> entitiesToPersist = new ArrayList<>();
int recordCount = 0;
for (final Map.Entry<Integer, List<GovernmentBodyAnnualSummary>> entry : data.entrySet()) {
final Integer year = entry.getKey();
final List<GovernmentBodyAnnualSummary> summaries = entry.getValue();
for (final GovernmentBodyAnnualSummary summary : summaries) {
final GovernmentBodyData entity = new GovernmentBodyData(
year,
summary.getName(),
summary.getConsecutiveNumber(),
summary.getGovermentBodyId(),
summary.getmCode(),
summary.getMinistry(),
summary.getOrgNumber(),
summary.getHeadCount(),
summary.getAnnualWorkHeadCount(),
summary.getVat(),
summary.getComment()
);
entitiesToPersist.add(entity);
recordCount++;
}
}
// Use batch persist for better performance
if (!entitiesToPersist.isEmpty()) {
governmentBodyDataDAO.persist(entitiesToPersist);
LOGGER.info("Loaded {} government body records from ESV", recordCount);
} else {
LOGGER.warn("No government body records found in ESV data");
}
}
/**
* Clear authentication.
*/
private static void clearAuthentication() {
SecurityContextHolder.getContext().setAuthentication(null);
}
/**
* Configure authentication.
*
* @param role the role
*/
private static void configureAuthentication(final String role) {
final Collection<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList(role);
final Authentication authentication = new UsernamePasswordAuthenticationToken("service.impl.GovernmentBodyDataLoaderService", "n/a", authorities);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}