package org.ovirt.engine.core.bll; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import org.ovirt.engine.core.bll.utils.IconUtils; import org.ovirt.engine.core.bll.validator.IconValidator; import org.ovirt.engine.core.common.businessentities.VmBase; import org.ovirt.engine.core.common.businessentities.VmIconDefault; import org.ovirt.engine.core.common.businessentities.VmStatic; import org.ovirt.engine.core.common.businessentities.VmTemplate; import org.ovirt.engine.core.common.osinfo.OsRepository; import org.ovirt.engine.core.common.queries.VmIconIdSizePair; import org.ovirt.engine.core.common.utils.SimpleDependencyInjector; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dal.dbbroker.DbFacade; import org.ovirt.engine.core.dao.VmStaticDao; import org.ovirt.engine.core.dao.VmTemplateDao; import org.ovirt.engine.core.utils.EngineLocalConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * It loads icons from packaging/icons/{small|large} dirs referenced from * packaging/conf/osinfo-defaults.properties by os name keys. * <p> * It * <ul> * <li>adds/updates icons to/in vm_icons table</li> * <li>regenerates vm_icon_defaults table</li> * <li>sets default icons according to OS for VMs and Templates in vm_static * table if at least one icon is missing; * this is only useful during the first run and to fix inconsistencies</li> * </ul> */ public class IconLoader { private static final Logger log = LoggerFactory.getLogger(IconLoader.class); private static final Path ICONS_DIR = EngineLocalConfig.getInstance().getUsrDir().toPath().resolve("icons"); private static final Path LARGE_ICON_DIR =ICONS_DIR.resolve("large"); private static final Path SMALL_ICON_DIR =ICONS_DIR.resolve("small"); private final Map<Integer, VmIconIdSizePair> osIdToIconIdMap = new HashMap<>(); private final int DEFAULT_OS_ID = OsRepository.DEFAULT_X86_OS; private IconLoader() { loadIconsToDatabase(); ensureDefaultOsIconExists(); updateVmIconDefaultsTable(); updateVmStaticTable(); } private void loadIconsToDatabase() { final Map<Integer, String> osIdToOsNameMap = SimpleDependencyInjector.getInstance().get(OsRepository.class).getUniqueOsNames(); for (Map.Entry<Integer, String> entry : osIdToOsNameMap.entrySet()) { final VmIconIdSizePair iconIdPair = ensureIconsInDatabase(entry.getValue()); if (iconIdPair != null) { osIdToIconIdMap.put(entry.getKey(), iconIdPair); } } } private void updateVmStaticTable() { final VmStaticDao vmStaticDao = DbFacade.getInstance().getVmStaticDao(); for (VmStatic vmStatic : vmStaticDao.getAllWithoutIcon()) { setIconsByOs(vmStatic); vmStaticDao.update(vmStatic); } final VmTemplateDao vmTemplateDao = DbFacade.getInstance().getVmTemplateDao(); for (VmTemplate vmTemplate : vmTemplateDao.getAllWithoutIcon()) { setIconsByOs(vmTemplate); vmTemplateDao.update(vmTemplate); } } private void setIconsByOs(VmBase vmBase) { final VmIconIdSizePair iconIdPair = getIconIdPairByOsId(vmBase.getOsId()); vmBase.setSmallIconId(iconIdPair.getSmall()); vmBase.setLargeIconId(iconIdPair.getLarge()); } private VmIconIdSizePair getIconIdPairByOsId(int osId) { final VmIconIdSizePair osDefaultIcons = osIdToIconIdMap.get(osId); if (osDefaultIcons != null) { return osDefaultIcons; } return osIdToIconIdMap.get(DEFAULT_OS_ID); } /** * It recreates 'vm_icon_defaults' table based on new configuration. */ private void updateVmIconDefaultsTable() { DbFacade.getInstance().getVmIconsDefaultDao().removeAll(); for (Map.Entry<Integer, VmIconIdSizePair> entry : osIdToIconIdMap.entrySet()) { final VmIconDefault osDefautlIconIds = new VmIconDefault(Guid.newGuid(), entry.getKey(), entry.getValue().getSmall(), entry.getValue().getLarge()); DbFacade.getInstance().getVmIconsDefaultDao().save(osDefautlIconIds); } } private void ensureDefaultOsIconExists() { if (osIdToIconIdMap.get(DEFAULT_OS_ID) == null) { throw new RuntimeException("Icons for default os not found."); } } public static void load() { new IconLoader(); } private static VmIconIdSizePair ensureIconsInDatabase(String osName) { final Guid smallIconId = ensureIconInDatabase(SMALL_ICON_DIR, osName); final Guid largeIconId = ensureIconInDatabase(LARGE_ICON_DIR, osName); if (smallIconId != null && largeIconId != null) { return new VmIconIdSizePair(smallIconId, largeIconId); } return null; } private static Guid ensureIconInDatabase(Path dir, String osName) { try { return ensureIconInDatabaseUnchecked(dir, osName); } catch (RuntimeException e) { log.warn(e.toString()); return null; } } private static Guid ensureIconInDatabaseUnchecked(Path dir, String osName) { final ResolvedIcon resolvedIcon = resolveIconName(dir, osName); final String dataUrl = loadIcon(resolvedIcon); return DbFacade.getInstance().getVmIconDao().ensureIconInDatabase(dataUrl); } private static String loadIcon(ResolvedIcon resolvedIcon) { try { final byte[] bytes = Files.readAllBytes(resolvedIcon.getPath()); return IconUtils.toDataUrl(bytes, resolvedIcon.getType()); } catch (IOException e) { throw new RuntimeException("Icon " + resolvedIcon.getPath() + "can't be open."); } } private static ResolvedIcon resolveIconName(Path dir, String osName) { for (IconValidator.FileType fileType : IconValidator.FileType.values()) { for (String extension : fileType.getExtensions()) { final Path iconPath = dir.resolve(osName + "." + extension); if (iconPath.toFile().exists()) { return new ResolvedIcon(iconPath, fileType); } } } throw new RuntimeException("Icon for " + osName + " was not found in " + dir); } private static class ResolvedIcon { private final Path path; private final IconValidator.FileType type; public ResolvedIcon(Path path, IconValidator.FileType type) { this.path = path; this.type = type; } public Path getPath() { return path; } public IconValidator.FileType getType() { return type; } } }