package fr.openwide.core.jpa.more.util.init.service; import static fr.openwide.core.jpa.more.property.JpaMorePropertyIds.DATABASE_INITIALIZED; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanWrapper; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.convert.converter.GenericConverter; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.core.convert.support.GenericConversionService; import org.springframework.security.crypto.password.PasswordEncoder; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import de.schlichtherle.truezip.file.TFileInputStream; import fr.openwide.core.commons.util.FileUtils; import fr.openwide.core.jpa.business.generic.model.GenericEntity; import fr.openwide.core.jpa.exception.SecurityServiceException; import fr.openwide.core.jpa.exception.ServiceException; import fr.openwide.core.jpa.more.business.generic.model.GenericListItem; import fr.openwide.core.jpa.more.business.generic.model.GenericLocalizedGenericListItem; import fr.openwide.core.jpa.more.util.init.dao.IImportDataDao; import fr.openwide.core.jpa.more.util.init.util.GenericEntityConverter; import fr.openwide.core.jpa.more.util.init.util.WorkbookUtils; import fr.openwide.core.spring.property.service.IPropertyService; import fr.openwide.core.spring.util.ReflectionUtils; import fr.openwide.core.spring.util.SpringBeanUtils; import fr.openwide.core.spring.util.StringUtils; public abstract class AbstractImportDataServiceImpl implements IImportDataService { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractImportDataServiceImpl.class); protected static final String REFERENCE_DATA_FILE = "reference_data.xls"; protected static final String BUSINESS_DATA_FILE = "business_data.xls"; private static final String ID_FIELD_NAME = "id"; private static final String CREATION_DATE_FIELD_NAME = "creationDate"; private static final String LAST_UPDATE_DATE_FIELD_NAME = "lastUpdateDate"; private static final String PASSWORD_FIELD_NAME = "password"; private static final String PASSWORD_HASH_FIELD_NAME = "passwordHash"; private static final Map<Class<?>, List<Class<?>>> ADDITIONAL_CLASS_MAPPINGS = new HashMap<Class<?>, List<Class<?>>>(); private static final Map<Class<?>, String> SHEET_NAME_MAPPING = new HashMap<Class<?>, String>(); @Autowired private IImportDataDao importDataDao; @Autowired private IPropertyService propertyService; @Autowired private PasswordEncoder passwordEncoder; @Override public void importDirectory(File directory) throws ServiceException, SecurityServiceException, FileNotFoundException, IOException { Map<String, Map<String, GenericEntity<Long, ?>>> idsMapping = new HashMap<String, Map<String, GenericEntity<Long, ?>>>(); importBeforeReferenceData(directory, idsMapping); LOGGER.info("Importing {}", REFERENCE_DATA_FILE); Workbook genericListItemWorkbook = new HSSFWorkbook(new TFileInputStream(FileUtils.getFile(directory, REFERENCE_DATA_FILE))); importGenericListItems(idsMapping, genericListItemWorkbook); LOGGER.info("Import of {} complete", REFERENCE_DATA_FILE); importAfterReferenceData(directory, idsMapping); importBeforeBusinessData(directory, idsMapping); LOGGER.info("Importing {}", BUSINESS_DATA_FILE); Workbook businessItemWorkbook = new HSSFWorkbook(new TFileInputStream(FileUtils.getFile(directory, BUSINESS_DATA_FILE))); importMainBusinessItems(idsMapping, businessItemWorkbook); LOGGER.info("Import of {} complete", BUSINESS_DATA_FILE); importAfterBusinessData(directory, idsMapping); importFiles(directory, idsMapping); propertyService.set(DATABASE_INITIALIZED, true); LOGGER.info("Import complete"); } protected void importBeforeReferenceData(File directory, Map<String, Map<String, GenericEntity<Long, ?>>> idsMapping) throws ServiceException, SecurityServiceException, FileNotFoundException, IOException { // nothing, override if necessary } protected void importAfterReferenceData(File directory, Map<String, Map<String, GenericEntity<Long, ?>>> idsMapping) throws ServiceException, SecurityServiceException, FileNotFoundException, IOException { // nothing, override if necessary } protected void importBeforeBusinessData(File directory, Map<String, Map<String, GenericEntity<Long, ?>>> idsMapping) throws ServiceException, SecurityServiceException, FileNotFoundException, IOException { // nothing, override if necessary } protected void importAfterBusinessData(File directory, Map<String, Map<String, GenericEntity<Long, ?>>> idsMapping) throws ServiceException, SecurityServiceException, FileNotFoundException, IOException { // nothing, override if necessary } protected abstract List<String> getGenericListItemPackagesToScan(); @SuppressWarnings({ "rawtypes", "unchecked" }) protected void importGenericListItems(Map<String, Map<String, GenericEntity<Long, ?>>> idsMapping, Workbook workbook) { for (String packageToScan : getGenericListItemPackagesToScan()) { Set<Class<? extends GenericEntity>> classes = Sets.newHashSet(); classes.addAll(ReflectionUtils.findAssignableClasses(packageToScan, GenericListItem.class)); classes.addAll(ReflectionUtils.findAssignableClasses(packageToScan, GenericLocalizedGenericListItem.class)); Map<Integer, Class<? extends GenericEntity>> orderedClasses = Maps.newTreeMap(); for (Class<? extends GenericEntity> genericListItemClass : classes) { Sheet sheet = workbook.getSheet(getSheetName(genericListItemClass)); if (sheet != null) { orderedClasses.put(sheet.getWorkbook().getSheetIndex(sheet), genericListItemClass); } } for (Class<? extends GenericEntity> genericListItemClass : orderedClasses.values()) { doImportItem(idsMapping, workbook, genericListItemClass); } } } protected abstract void importMainBusinessItems(Map<String, Map<String, GenericEntity<Long, ?>>> idsMapping, Workbook workbook); protected void importFiles(File directory, Map<String, Map<String, GenericEntity<Long, ?>>> idsMapping) throws ServiceException, SecurityServiceException { // nothing, override if necessary } protected <E extends GenericEntity<Long, ?>> void doImportItem(Map<String, Map<String, GenericEntity<Long, ?>>> idsMapping, Workbook workbook, Class<E> clazz) { Sheet sheet = workbook.getSheet(getSheetName(clazz)); if (sheet != null) { GenericEntityConverter converter = new GenericEntityConverter(importDataDao, workbook, new HashMap<Class<?>, Class<?>>(0), idsMapping); GenericConversionService conversionService = getConversionService(converter); converter.setConversionService(conversionService); Map<String, GenericEntity<Long, ?>> idsMappingForClass = idsMapping.get(clazz.getName()); if (idsMappingForClass == null) { idsMappingForClass = new HashMap<String, GenericEntity<Long, ?>>(); idsMapping.put(clazz.getName(), idsMappingForClass); } for (Class<?> referencedClass : getOtherReferencedClasses(clazz)) { if (!idsMapping.containsKey(referencedClass.getName())) { idsMapping.put(referencedClass.getName(), new HashMap<String, GenericEntity<Long, ?>>()); } } for (Map<String, Object> line : WorkbookUtils.getSheetContent(sheet)) { E item = BeanUtils.instantiateClass(clazz); String importId = StringUtils.trimWhitespace(Objects.toString(line.get(ID_FIELD_NAME), null)); line.remove(ID_FIELD_NAME); doFilterLine(clazz, line); BeanWrapper wrapper = SpringBeanUtils.getBeanWrapper(item); wrapper.setConversionService(conversionService); wrapper.setPropertyValues(new MutablePropertyValues(line), true); importDataDao.create(item); afterImportItem(item); idsMappingForClass.put(importId, item); for (Class<?> referencedClass : getOtherReferencedClasses(clazz)) { idsMapping.get(referencedClass.getName()).put(importId, item); } } LOGGER.info("Imported " + idsMappingForClass.size() + " objects for class: " + clazz.getSimpleName()); } else { LOGGER.info("Nothing to do for class: " + clazz.getSimpleName()); } } protected <E extends GenericEntity<Long, ?>> void doFilterLine(Class<E> clazz, Map<String, Object> line) { Date creationDate = new Date(); if (!line.containsKey(CREATION_DATE_FIELD_NAME)) { line.put(CREATION_DATE_FIELD_NAME, creationDate); } if (!line.containsKey(LAST_UPDATE_DATE_FIELD_NAME)) { line.put(LAST_UPDATE_DATE_FIELD_NAME, creationDate); } if (line.containsKey(PASSWORD_FIELD_NAME)) { line.put(PASSWORD_HASH_FIELD_NAME, passwordEncoder.encode(line.get(PASSWORD_FIELD_NAME).toString())); } } protected void addAdditionalClassMapping(Class<?> sourceClass, Class<?> targetClass) { if (!ADDITIONAL_CLASS_MAPPINGS.containsKey(sourceClass)) { ADDITIONAL_CLASS_MAPPINGS.put(sourceClass, new ArrayList<Class<?>>()); } ADDITIONAL_CLASS_MAPPINGS.get(sourceClass).add(targetClass); } protected List<Class<?>> getOtherReferencedClasses(Class<?> sourceClass) { if (ADDITIONAL_CLASS_MAPPINGS.containsKey(sourceClass)) { return ADDITIONAL_CLASS_MAPPINGS.get(sourceClass); } else { return new ArrayList<Class<?>>(0); } } protected void setSheetNameMapping(Class<?> clazz, String sheetName) { SHEET_NAME_MAPPING.put(clazz, sheetName); } protected String getSheetName(Class<?> clazz) { if (SHEET_NAME_MAPPING.containsKey(clazz)) { return SHEET_NAME_MAPPING.get(clazz); } else { return clazz.getSimpleName(); } } private GenericConversionService getConversionService(GenericConverter... converters) { GenericConversionService service = new GenericConversionService(); for (GenericConverter converter : converters) { service.addConverter(converter); } DefaultConversionService.addDefaultConverters(service); return service; } protected <E extends GenericEntity<Long, ?>> void afterImportItem(E item) { } }