/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.openmeetings.backup; import static java.util.UUID.randomUUID; import static org.apache.openmeetings.db.bind.Constants.APPOINTMENT_LIST_NODE; import static org.apache.openmeetings.db.bind.Constants.APPOINTMENT_NODE; import static org.apache.openmeetings.db.bind.Constants.CALENDAR_LIST_NODE; import static org.apache.openmeetings.db.bind.Constants.CALENDAR_NODE; import static org.apache.openmeetings.db.bind.Constants.CFG_LIST_NODE; import static org.apache.openmeetings.db.bind.Constants.CFG_NODE; import static org.apache.openmeetings.db.bind.Constants.CHAT_LIST_NODE; import static org.apache.openmeetings.db.bind.Constants.CHAT_NODE; import static org.apache.openmeetings.db.bind.Constants.CONTACT_LIST_NODE; import static org.apache.openmeetings.db.bind.Constants.CONTACT_NODE; import static org.apache.openmeetings.db.bind.Constants.FILE_LIST_NODE; import static org.apache.openmeetings.db.bind.Constants.FILE_NODE; import static org.apache.openmeetings.db.bind.Constants.GROUP_LIST_NODE; import static org.apache.openmeetings.db.bind.Constants.GROUP_NODE; import static org.apache.openmeetings.db.bind.Constants.MMEMBER_LIST_NODE; import static org.apache.openmeetings.db.bind.Constants.MMEMBER_NODE; import static org.apache.openmeetings.db.bind.Constants.MSG_FOLDER_LIST_NODE; import static org.apache.openmeetings.db.bind.Constants.MSG_FOLDER_NODE; import static org.apache.openmeetings.db.bind.Constants.MSG_LIST_NODE; import static org.apache.openmeetings.db.bind.Constants.MSG_NODE; import static org.apache.openmeetings.db.bind.Constants.OAUTH_LIST_NODE; import static org.apache.openmeetings.db.bind.Constants.OAUTH_NODE; import static org.apache.openmeetings.db.bind.Constants.POLL_LIST_NODE; import static org.apache.openmeetings.db.bind.Constants.POLL_NODE; import static org.apache.openmeetings.db.bind.Constants.RECORDING_LIST_NODE; import static org.apache.openmeetings.db.bind.Constants.RECORDING_NODE; import static org.apache.openmeetings.db.bind.Constants.ROOM_FILE_LIST_NODE; import static org.apache.openmeetings.db.bind.Constants.ROOM_FILE_NODE; import static org.apache.openmeetings.db.bind.Constants.ROOM_GRP_LIST_NODE; import static org.apache.openmeetings.db.bind.Constants.ROOM_GRP_NODE; import static org.apache.openmeetings.db.bind.Constants.ROOM_LIST_NODE; import static org.apache.openmeetings.db.bind.Constants.ROOM_NODE; import static org.apache.openmeetings.db.bind.Constants.USER_LIST_NODE; import static org.apache.openmeetings.db.bind.Constants.USER_NODE; import static org.apache.openmeetings.db.bind.Constants.VERSION_LIST_NODE; import static org.apache.openmeetings.db.bind.Constants.VERSION_NODE; import static org.apache.openmeetings.db.entity.user.PrivateMessage.INBOX_FOLDER_ID; import static org.apache.openmeetings.db.entity.user.PrivateMessage.SENT_FOLDER_ID; import static org.apache.openmeetings.db.entity.user.PrivateMessage.TRASH_FOLDER_ID; import static org.apache.openmeetings.util.OmFileHelper.BCKP_RECORD_FILES; import static org.apache.openmeetings.util.OmFileHelper.BCKP_ROOM_FILES; import static org.apache.openmeetings.util.OmFileHelper.CSS_DIR; import static org.apache.openmeetings.util.OmFileHelper.EXTENSION_CSS; import static org.apache.openmeetings.util.OmFileHelper.EXTENSION_JPG; import static org.apache.openmeetings.util.OmFileHelper.EXTENSION_MP4; import static org.apache.openmeetings.util.OmFileHelper.EXTENSION_PNG; import static org.apache.openmeetings.util.OmFileHelper.FILES_DIR; import static org.apache.openmeetings.util.OmFileHelper.FILE_NAME_FMT; import static org.apache.openmeetings.util.OmFileHelper.GROUP_CSS_PREFIX; import static org.apache.openmeetings.util.OmFileHelper.GROUP_LOGO_DIR; import static org.apache.openmeetings.util.OmFileHelper.GROUP_LOGO_PREFIX; import static org.apache.openmeetings.util.OmFileHelper.PROFILES_DIR; import static org.apache.openmeetings.util.OmFileHelper.PROFILES_PREFIX; import static org.apache.openmeetings.util.OmFileHelper.RECORDING_FILE_NAME; import static org.apache.openmeetings.util.OmFileHelper.WML_DIR; import static org.apache.openmeetings.util.OmFileHelper.getCssDir; import static org.apache.openmeetings.util.OmFileHelper.getFileExt; import static org.apache.openmeetings.util.OmFileHelper.getFileName; import static org.apache.openmeetings.util.OmFileHelper.getGroupCss; import static org.apache.openmeetings.util.OmFileHelper.getGroupLogo; import static org.apache.openmeetings.util.OmFileHelper.getName; import static org.apache.openmeetings.util.OmFileHelper.getStreamsHibernateDir; import static org.apache.openmeetings.util.OmFileHelper.getUploadFilesDir; import static org.apache.openmeetings.util.OmFileHelper.getUploadProfilesUserDir; import static org.apache.openmeetings.util.OmFileHelper.getUploadWmlDir; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_APPOINTMENT_REMINDER_MINUTES; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_CALENDAR_ROOM_CAPACITY; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_CAM_FPS; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_CRYPT; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_CSP_FRAME; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_DASHBOARD_RSS_FEED1; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_DASHBOARD_RSS_FEED2; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_DASHBOARD_SHOW_CHAT; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_DASHBOARD_SHOW_MYROOMS; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_DASHBOARD_SHOW_RSS; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_DEFAULT_GROUP_ID; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_DEFAULT_LANG; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_DEFAULT_LDAP_ID; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_DOCUMENT_DPI; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_DOCUMENT_QUALITY; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_EMAIL_AT_REGISTER; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_EMAIL_VERIFICATION; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_EXT_PROCESS_TTL; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_IGNORE_BAD_SSL; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_KEYCODE_ARRANGE; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_KEYCODE_MUTE; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_KEYCODE_MUTE_OTHERS; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_LOGIN_MIN_LENGTH; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_MAX_UPLOAD_SIZE; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_MIC_ECHO; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_MIC_NOISE; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_MIC_RATE; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_MYROOMS_ENABLED; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_PASS_MIN_LENGTH; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_PATH_FFMPEG; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_PATH_IMAGEMAGIC; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_PATH_OFFICE; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_PATH_SOX; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_REGISTER_FRONTEND; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_REGISTER_OAUTH; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_REGISTER_SOAP; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_REMINDER_MESSAGE; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_REPLY_TO_ORGANIZER; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_SCREENSHARING_ALLOW_REMOTE; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_SCREENSHARING_FPS; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_SCREENSHARING_FPS_SHOW; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_SCREENSHARING_QUALITY; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_SIP_ENABLED; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_SIP_EXTEN_CONTEXT; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_SIP_ROOM_PREFIX; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_SMTP_PASS; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_SMTP_PORT; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_SMTP_SERVER; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_SMTP_SYSTEM_EMAIL; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_SMTP_TIMEOUT; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_SMTP_TIMEOUT_CON; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_SMTP_TLS; import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_SMTP_USER; import static org.apache.openmeetings.util.OpenmeetingsVariables.getDefaultTimezone; import static org.apache.openmeetings.util.OpenmeetingsVariables.getMinLoginLength; import java.awt.event.KeyEvent; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Set; import java.util.TreeMap; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamReader; import javax.xml.transform.stream.StreamSource; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.text.WordUtils; import org.apache.openmeetings.backup.converter.WbConverter; import org.apache.openmeetings.core.converter.DocumentConverter; import org.apache.openmeetings.db.bind.adapter.AppointmentAdapter; import org.apache.openmeetings.db.bind.adapter.FileAdapter; import org.apache.openmeetings.db.bind.adapter.GroupAdapter; import org.apache.openmeetings.db.bind.adapter.OmCalendarAdapter; import org.apache.openmeetings.db.bind.adapter.RoomAdapter; import org.apache.openmeetings.db.bind.adapter.UserAdapter; import org.apache.openmeetings.db.dao.basic.ChatDao; import org.apache.openmeetings.db.dao.basic.ConfigurationDao; import org.apache.openmeetings.db.dao.calendar.AppointmentDao; import org.apache.openmeetings.db.dao.calendar.MeetingMemberDao; import org.apache.openmeetings.db.dao.calendar.OmCalendarDao; import org.apache.openmeetings.db.dao.file.BaseFileItemDao; import org.apache.openmeetings.db.dao.file.FileItemDao; import org.apache.openmeetings.db.dao.record.RecordingDao; import org.apache.openmeetings.db.dao.room.PollDao; import org.apache.openmeetings.db.dao.room.RoomDao; import org.apache.openmeetings.db.dao.server.LdapConfigDao; import org.apache.openmeetings.db.dao.server.OAuth2Dao; import org.apache.openmeetings.db.dao.user.GroupDao; import org.apache.openmeetings.db.dao.user.PrivateMessageDao; import org.apache.openmeetings.db.dao.user.PrivateMessageFolderDao; import org.apache.openmeetings.db.dao.user.UserContactDao; import org.apache.openmeetings.db.dao.user.UserDao; import org.apache.openmeetings.db.dto.room.Whiteboard; import org.apache.openmeetings.db.entity.basic.ChatMessage; import org.apache.openmeetings.db.entity.basic.Configuration; import org.apache.openmeetings.db.entity.calendar.Appointment; import org.apache.openmeetings.db.entity.calendar.MeetingMember; import org.apache.openmeetings.db.entity.calendar.OmCalendar; import org.apache.openmeetings.db.entity.file.BaseFileItem; import org.apache.openmeetings.db.entity.file.FileItem; import org.apache.openmeetings.db.entity.record.Recording; import org.apache.openmeetings.db.entity.record.RecordingChunk; import org.apache.openmeetings.db.entity.room.Room; import org.apache.openmeetings.db.entity.room.RoomFile; import org.apache.openmeetings.db.entity.room.RoomGroup; import org.apache.openmeetings.db.entity.room.RoomModerator; import org.apache.openmeetings.db.entity.room.RoomPoll; import org.apache.openmeetings.db.entity.room.RoomPollAnswer; import org.apache.openmeetings.db.entity.server.LdapConfig; import org.apache.openmeetings.db.entity.server.OAuthServer; import org.apache.openmeetings.db.entity.user.Group; import org.apache.openmeetings.db.entity.user.GroupUser; import org.apache.openmeetings.db.entity.user.PrivateMessage; import org.apache.openmeetings.db.entity.user.PrivateMessageFolder; import org.apache.openmeetings.db.entity.user.User; import org.apache.openmeetings.db.entity.user.UserContact; import org.apache.openmeetings.db.util.AuthLevelUtil; import org.apache.openmeetings.db.util.XmlHelper; import org.apache.openmeetings.util.CalendarPatterns; import org.apache.openmeetings.util.OmFileHelper; import org.apache.openmeetings.util.StoredFile; import org.apache.openmeetings.util.crypt.SCryptImplementation; import org.apache.wicket.util.string.Strings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class BackupImport { private static final Logger log = LoggerFactory.getLogger(BackupImport.class); private static final Map<String, String> outdatedConfigKeys = new HashMap<>(); private static final Map<String, Configuration.Type> configTypes = new HashMap<>(); private static final Pattern UUID_PATTERN = Pattern.compile("^[\\da-f]{8}(?:-[\\da-f]{4}){3}-[\\da-f]{12}$"); static { outdatedConfigKeys.put("crypt_ClassName", CONFIG_CRYPT); outdatedConfigKeys.put("system_email_addr", CONFIG_SMTP_SYSTEM_EMAIL); outdatedConfigKeys.put("smtp_server", CONFIG_SMTP_SERVER); outdatedConfigKeys.put("smtp_port", CONFIG_SMTP_PORT); outdatedConfigKeys.put("email_username", CONFIG_SMTP_USER); outdatedConfigKeys.put("email_userpass", CONFIG_SMTP_PASS); outdatedConfigKeys.put("default_lang_id", CONFIG_DEFAULT_LANG); outdatedConfigKeys.put("allow_frontend_register", CONFIG_REGISTER_FRONTEND); outdatedConfigKeys.put("max_upload_size", CONFIG_MAX_UPLOAD_SIZE); outdatedConfigKeys.put("rss_feed1", CONFIG_DASHBOARD_RSS_FEED1); outdatedConfigKeys.put("rss_feed2", CONFIG_DASHBOARD_RSS_FEED2); outdatedConfigKeys.put("oauth2.ignore_bad_ssl", CONFIG_IGNORE_BAD_SSL); outdatedConfigKeys.put("default.quality.screensharing", CONFIG_SCREENSHARING_QUALITY); outdatedConfigKeys.put("default.fps.screensharing", CONFIG_SCREENSHARING_FPS); outdatedConfigKeys.put("ldap_default_id", CONFIG_DEFAULT_LDAP_ID); outdatedConfigKeys.put("default_group_id", CONFIG_DEFAULT_GROUP_ID); outdatedConfigKeys.put("imagemagick_path", CONFIG_PATH_IMAGEMAGIC); outdatedConfigKeys.put("sox_path", CONFIG_PATH_SOX); outdatedConfigKeys.put("ffmpeg_path", CONFIG_PATH_FFMPEG); outdatedConfigKeys.put("office.path", CONFIG_PATH_OFFICE); outdatedConfigKeys.put("red5sip.enable", CONFIG_SIP_ENABLED); outdatedConfigKeys.put("red5sip.room_prefix", CONFIG_SIP_ROOM_PREFIX); outdatedConfigKeys.put("red5sip.exten_context", CONFIG_SIP_EXTEN_CONTEXT); outdatedConfigKeys.put("sendEmailAtRegister", CONFIG_EMAIL_AT_REGISTER); outdatedConfigKeys.put("sendEmailWithVerficationCode", CONFIG_EMAIL_VERIFICATION); outdatedConfigKeys.put("swftools_zoom", CONFIG_DOCUMENT_DPI); outdatedConfigKeys.put("swftools_jpegquality", CONFIG_DOCUMENT_QUALITY); outdatedConfigKeys.put("sms.subject", CONFIG_REMINDER_MESSAGE); outdatedConfigKeys.put("exclusive.audio.keycode", CONFIG_KEYCODE_MUTE_OTHERS); outdatedConfigKeys.put("header.csp.frame.options", CONFIG_CSP_FRAME); configTypes.put(CONFIG_REGISTER_FRONTEND, Configuration.Type.BOOL); configTypes.put(CONFIG_REGISTER_SOAP, Configuration.Type.BOOL); configTypes.put(CONFIG_REGISTER_OAUTH, Configuration.Type.BOOL); configTypes.put(CONFIG_SMTP_TLS, Configuration.Type.BOOL); configTypes.put(CONFIG_EMAIL_AT_REGISTER, Configuration.Type.BOOL); configTypes.put(CONFIG_EMAIL_VERIFICATION, Configuration.Type.BOOL); configTypes.put(CONFIG_SIP_ENABLED, Configuration.Type.BOOL); configTypes.put(CONFIG_SCREENSHARING_FPS_SHOW, Configuration.Type.BOOL); configTypes.put(CONFIG_SCREENSHARING_ALLOW_REMOTE, Configuration.Type.BOOL); configTypes.put(CONFIG_DASHBOARD_SHOW_MYROOMS, Configuration.Type.BOOL); configTypes.put(CONFIG_DASHBOARD_SHOW_CHAT, Configuration.Type.BOOL); configTypes.put(CONFIG_DASHBOARD_SHOW_RSS, Configuration.Type.BOOL); configTypes.put(CONFIG_REPLY_TO_ORGANIZER, Configuration.Type.BOOL); configTypes.put(CONFIG_IGNORE_BAD_SSL, Configuration.Type.BOOL); configTypes.put(CONFIG_MYROOMS_ENABLED, Configuration.Type.BOOL); configTypes.put(CONFIG_DEFAULT_GROUP_ID, Configuration.Type.NUMBER); configTypes.put(CONFIG_SMTP_PORT, Configuration.Type.NUMBER); configTypes.put(CONFIG_SMTP_TIMEOUT_CON, Configuration.Type.NUMBER); configTypes.put(CONFIG_SMTP_TIMEOUT, Configuration.Type.NUMBER); configTypes.put(CONFIG_DEFAULT_LANG, Configuration.Type.NUMBER); configTypes.put(CONFIG_DOCUMENT_DPI, Configuration.Type.NUMBER); configTypes.put(CONFIG_DOCUMENT_QUALITY, Configuration.Type.NUMBER); configTypes.put(CONFIG_SCREENSHARING_QUALITY, Configuration.Type.NUMBER); configTypes.put(CONFIG_SCREENSHARING_FPS, Configuration.Type.NUMBER); configTypes.put(CONFIG_MAX_UPLOAD_SIZE, Configuration.Type.NUMBER); configTypes.put(CONFIG_APPOINTMENT_REMINDER_MINUTES, Configuration.Type.NUMBER); configTypes.put(CONFIG_LOGIN_MIN_LENGTH, Configuration.Type.NUMBER); configTypes.put(CONFIG_PASS_MIN_LENGTH, Configuration.Type.NUMBER); configTypes.put(CONFIG_CALENDAR_ROOM_CAPACITY, Configuration.Type.NUMBER); configTypes.put(CONFIG_KEYCODE_ARRANGE, Configuration.Type.HOTKEY); configTypes.put(CONFIG_KEYCODE_MUTE_OTHERS, Configuration.Type.HOTKEY); configTypes.put(CONFIG_KEYCODE_MUTE, Configuration.Type.HOTKEY); configTypes.put(CONFIG_DEFAULT_LDAP_ID, Configuration.Type.NUMBER); configTypes.put(CONFIG_CAM_FPS, Configuration.Type.NUMBER); configTypes.put(CONFIG_MIC_RATE, Configuration.Type.NUMBER); configTypes.put(CONFIG_MIC_ECHO, Configuration.Type.BOOL); configTypes.put(CONFIG_MIC_NOISE, Configuration.Type.BOOL); configTypes.put(CONFIG_EXT_PROCESS_TTL, Configuration.Type.NUMBER); } @Autowired private AppointmentDao appointmentDao; @Autowired private OmCalendarDao calendarDao; @Autowired private RoomDao roomDao; @Autowired private UserDao userDao; @Autowired private RecordingDao recordingDao; @Autowired private PrivateMessageFolderDao privateMessageFolderDao; @Autowired private PrivateMessageDao privateMessageDao; @Autowired private MeetingMemberDao meetingMemberDao; @Autowired private LdapConfigDao ldapConfigDao; @Autowired private FileItemDao fileItemDao; @Autowired private UserContactDao userContactDao; @Autowired private PollDao pollDao; @Autowired private ConfigurationDao cfgDao; @Autowired private ChatDao chatDao; @Autowired private OAuth2Dao auth2Dao; @Autowired private GroupDao groupDao; @Autowired private DocumentConverter docConverter; private final Map<Long, Long> ldapMap = new HashMap<>(); private final Map<Long, Long> oauthMap = new HashMap<>(); private final Map<Long, Long> userMap = new HashMap<>(); private final Map<Long, Long> groupMap = new HashMap<>(); private final Map<Long, Long> calendarMap = new HashMap<>(); private final Map<Long, Long> appointmentMap = new HashMap<>(); private final Map<Long, Long> roomMap = new HashMap<>(); private final Map<Long, Long> fileItemMap = new HashMap<>(); private final Map<Long, Long> messageFolderMap = new HashMap<>(); private final Map<Long, Long> userContactMap = new HashMap<>(); private final Map<String, String> fileMap = new HashMap<>(); private final Map<String, String> hashMap = new HashMap<>(); private static File validate(String ename, File intended) throws IOException { final String intendedPath = intended.getCanonicalPath(); // for each entry to be extracted File fentry = new File(intended, ename); final String canonicalPath = fentry.getCanonicalPath(); if (canonicalPath.startsWith(intendedPath)) { return fentry; } else { throw new IllegalStateException("File is outside extraction target directory."); } } private static File unzip(InputStream is) throws IOException { File f = OmFileHelper.getNewDir(OmFileHelper.getUploadImportDir(), "import_" + CalendarPatterns.getTimeForStreamId(new Date())); log.debug("##### EXTRACTING BACKUP TO: {}", f); try (ZipInputStream zis = new ZipInputStream(is)) { ZipEntry zipentry = null; while ((zipentry = zis.getNextEntry()) != null) { // for each entry to be extracted File fentry = validate(zipentry.getName(), f); File dir = zipentry.isDirectory() ? fentry : fentry.getParentFile(); if (!dir.exists() && !dir.mkdirs()) { log.warn("Failed to create folders: {}", dir); } if (!fentry.isDirectory()) { try (FileOutputStream fos = FileUtils.openOutputStream(fentry)) { IOUtils.copy(zis, fos); } zis.closeEntry(); } } } return f; } public void performImport(InputStream is, ProgressHolder progressHolder) throws Exception { progressHolder.setProgress(0); cleanup(); messageFolderMap.put(INBOX_FOLDER_ID, INBOX_FOLDER_ID); messageFolderMap.put(SENT_FOLDER_ID, SENT_FOLDER_ID); messageFolderMap.put(TRASH_FOLDER_ID, TRASH_FOLDER_ID); File f = unzip(is); BackupVersion ver = getVersion(f); progressHolder.setProgress(2); importConfigs(f); progressHolder.setProgress(7); importGroups(f); progressHolder.setProgress(12); importLdap(f); progressHolder.setProgress(17); importOauth(f); progressHolder.setProgress(22); importUsers(f); progressHolder.setProgress(27); importRooms(f); progressHolder.setProgress(32); importRoomGroups(f); progressHolder.setProgress(37); importChat(f); progressHolder.setProgress(42); importCalendars(f); progressHolder.setProgress(47); importAppointments(f); progressHolder.setProgress(52); importMeetingMembers(f); progressHolder.setProgress(57); importRecordings(f); progressHolder.setProgress(62); importPrivateMsgFolders(f); progressHolder.setProgress(67); importContacts(f); progressHolder.setProgress(72); importPrivateMsgs(f); progressHolder.setProgress(77); List<FileItem> files = importFiles(f); progressHolder.setProgress(82); importPolls(f); progressHolder.setProgress(87); importRoomFiles(f); progressHolder.setProgress(92); log.info("Room files import complete, starting copy of files and folders"); /* * ##################### Import real files and folders */ importFolders(f); progressHolder.setProgress(97); if (ver.compareTo(BackupVersion.get("4.0.0")) < 0) { for (BaseFileItem bfi : files) { if (bfi.isDeleted()) { continue; } if (BaseFileItem.Type.PRESENTATION == bfi.getType()) { convertOldPresentation((FileItem)bfi); fileItemDao.updateBase(bfi); } if (BaseFileItem.Type.WML_FILE == bfi.getType()) { try { Whiteboard wb = WbConverter.convert((FileItem)bfi); wb.save(bfi.getFile().toPath()); } catch (Exception e) { log.error("Unexpected error while converting WB", e); } } } } log.info("File explorer item import complete, clearing temp files"); FileUtils.deleteDirectory(f); cleanup(); progressHolder.setProgress(100); } void cleanup() { ldapMap.clear(); oauthMap.clear(); userMap.clear(); groupMap.clear(); calendarMap.clear(); appointmentMap.clear(); roomMap.clear(); messageFolderMap.clear(); userContactMap.clear(); fileMap.clear(); hashMap.clear(); messageFolderMap.put(INBOX_FOLDER_ID, INBOX_FOLDER_ID); messageFolderMap.put(SENT_FOLDER_ID, SENT_FOLDER_ID); messageFolderMap.put(TRASH_FOLDER_ID, TRASH_FOLDER_ID); } static BackupVersion getVersion(File base) { List<BackupVersion> list = new ArrayList<>(1); readList(base, "version.xml", VERSION_LIST_NODE, VERSION_NODE, BackupVersion.class, v -> list.add(v), true); return list.isEmpty() ? new BackupVersion() : list.get(0); } /* * ##################### Import Configs */ void importConfigs(File base) throws Exception { final Map<Integer, String> keyMap = new HashMap<>(); Arrays.stream(KeyEvent.class.getDeclaredFields()) .filter(fld -> fld.getName().startsWith("VK_")) .forEach(fld -> { try { keyMap.put(fld.getInt(null), "Shift+" + WordUtils.capitalizeFully(fld.getName().substring(3))); } catch (IllegalArgumentException|IllegalAccessException e) { log.error("Unexpected exception while building KEY map {}", fld); } }); Class<Configuration> eClazz = Configuration.class; JAXBContext jc = JAXBContext.newInstance(eClazz); Unmarshaller unmarshaller = jc.createUnmarshaller(); unmarshaller.setAdapter(new UserAdapter(userDao, userMap)); readList(unmarshaller, base, "configs.xml", CFG_LIST_NODE, CFG_NODE, eClazz, c -> { if (c.getKey() == null || c.isDeleted()) { return; } String newKey = outdatedConfigKeys.get(c.getKey()); if (newKey != null) { c.setKey(newKey); } Configuration.Type type = configTypes.get(c.getKey()); if (type != null) { c.setType(type); if (Configuration.Type.BOOL == type) { c.setValue(String.valueOf("1".equals(c.getValue()) || "yes".equals(c.getValue()) || "true".equals(c.getValue()))); } else if (Configuration.Type.HOTKEY == type) { try { int val = c.getValueN().intValue(); c.setValue(keyMap.get(val)); } catch(Exception e) { //no-op, value is already HOTKEY } } } Configuration cfg = cfgDao.forceGet(c.getKey()); if (cfg != null && !cfg.isDeleted()) { log.warn("Non deleted configuration with same key is found! old value: {}, new value: {}", cfg.getValue(), c.getValue()); } c.setId(cfg == null ? null : cfg.getId()); if (c.getUser() != null && c.getUser().getId() == null) { c.setUser(null); } if (CONFIG_CRYPT.equals(c.getKey())) { try { Class<?> clazz = Class.forName(c.getValue()); clazz.getDeclaredConstructor().newInstance(); } catch (Exception e) { log.warn("Not existing Crypt class found {}, replacing with SCryptImplementation", c.getValue()); c.setValue(SCryptImplementation.class.getCanonicalName()); } } cfgDao.update(c, null); }); } /* * ##################### Import Groups */ void importGroups(File base) throws Exception { log.info("Configs import complete, starting group import"); readList(base, "organizations.xml", GROUP_LIST_NODE, GROUP_NODE, Group.class, g -> { Long oldId = g.getId(); g.setId(null); g = groupDao.update(g, null); groupMap.put(oldId, g.getId()); }); } /* * ##################### Import LDAP Configs */ Long importLdap(File base) { log.info("Groups import complete, starting LDAP config import"); Long[] defaultLdapId = {cfgDao.getLong(CONFIG_DEFAULT_LDAP_ID, null)}; readList(base, "ldapconfigs.xml", "ldapconfigs", "ldapconfig", LdapConfig.class, c -> { if (Strings.isEmpty(c.getName()) || "local DB [internal]".equals(c.getName())) { return; } Long oldId = c.getId(); c.setId(null); c = ldapConfigDao.update(c, null); if (defaultLdapId[0] == null) { defaultLdapId[0] = c.getId(); } if (oldId != null) { ldapMap.put(oldId, c.getId()); } }); return defaultLdapId[0]; } /* * ##################### OAuth2 servers */ void importOauth(File base) { log.info("Ldap config import complete, starting OAuth2 server import"); readList(base, "oauth2servers.xml", OAUTH_LIST_NODE, OAUTH_NODE, OAuthServer.class , s -> { Long oldId = s.getId(); s.setId(null); s = auth2Dao.update(s, null); if (oldId != null) { oauthMap.put(oldId, s.getId()); } }, false); } /* * ##################### Import Users */ void importUsers(File base) throws Exception { log.info("OAuth2 servers import complete, starting user import"); String jNameTimeZone = getDefaultTimezone(); //add existent emails from database List<User> users = userDao.getAllUsers(); final Set<String> userEmails = new HashSet<>(); final Set<UserKey> userLogins = new HashSet<>(); for (User u : users){ if (u.getAddress() != null && !Strings.isEmpty(u.getAddress().getEmail())) { userEmails.add(u.getAddress().getEmail()); } userLogins.add(new UserKey(u)); } Class<User> eClazz = User.class; JAXBContext jc = JAXBContext.newInstance(eClazz); Unmarshaller unmarshaller = jc.createUnmarshaller(); unmarshaller.setAdapter(new GroupAdapter(groupDao, groupMap)); int minLoginLength = getMinLoginLength(); readList(unmarshaller, base, "users.xml", USER_LIST_NODE, USER_NODE, eClazz, u -> { if (u.getLogin() == null || u.isDeleted()) { return; } // check that email is unique if (u.getAddress() != null && u.getAddress().getEmail() != null && User.Type.USER == u.getType()) { if (userEmails.contains(u.getAddress().getEmail())) { log.warn("Email is duplicated for user {}", u); String updateEmail = String.format("modified_by_import_<%s>%s", randomUUID(), u.getAddress().getEmail()); u.getAddress().setEmail(updateEmail); } userEmails.add(u.getAddress().getEmail()); } if (u.getType() == User.Type.LDAP) { if (u.getDomainId() != null && ldapMap.containsKey(u.getDomainId())) { u.setDomainId(ldapMap.get(u.getDomainId())); } else { log.error("Unable to find Domain for ID: {}", u.getDomainId()); } } if (u.getType() == User.Type.OAUTH) { if (u.getDomainId() != null && oauthMap.containsKey(u.getDomainId())) { u.setDomainId(oauthMap.get(u.getDomainId())); } else { log.error("Unable to find Domain for ID: {}", u.getDomainId()); } } if (userLogins.contains(new UserKey(u))) { log.warn("LOGIN is duplicated for USER {}", u); String updateLogin = String.format("modified_by_import_<%s>%s", randomUUID(), u.getLogin()); u.setLogin(updateLogin); } userLogins.add(new UserKey(u)); if (u.getGroupUsers() != null) { for (Iterator<GroupUser> iter = u.getGroupUsers().iterator(); iter.hasNext();) { GroupUser gu = iter.next(); if (gu.getGroup().getId() == null) { iter.remove(); continue; } gu.setUser(u); } } if (u.getType() == User.Type.CONTACT && u.getLogin().length() < minLoginLength) { u.setLogin(randomUUID().toString()); } String tz = u.getTimeZoneId(); if (tz == null) { u.setTimeZoneId(jNameTimeZone); } Long userId = u.getId(); u.setId(null); if (u.getSipUser() != null && u.getSipUser().getId() != 0) { u.getSipUser().setId(0); } if (AuthLevelUtil.hasLoginLevel(u.getRights()) && !Strings.isEmpty(u.getActivatehash())) { u.setActivatehash(null); } if (u.getExternalType() != null) { Group g = groupDao.getExternal(u.getExternalType()); u.addGroup(g); } userDao.update(u, Long.valueOf(-1)); userMap.put(userId, u.getId()); }); } /* * ##################### Import Rooms */ void importRooms(File base) throws Exception { log.info("Users import complete, starting room import"); Class<Room> eClazz = Room.class; JAXBContext jc = JAXBContext.newInstance(eClazz); Unmarshaller unmarshaller = jc.createUnmarshaller(); unmarshaller.setAdapter(new UserAdapter(userDao, userMap)); readList(unmarshaller, base, "rooms.xml", ROOM_LIST_NODE, ROOM_NODE, eClazz, r -> { Long roomId = r.getId(); // We need to reset ids as openJPA reject to store them otherwise r.setId(null); if (r.getModerators() != null) { for (Iterator<RoomModerator> i = r.getModerators().iterator(); i.hasNext();) { RoomModerator rm = i.next(); if (rm.getUser().getId() == null) { i.remove(); } } } r = roomDao.update(r, null); roomMap.put(roomId, r.getId()); }); } /* * ##################### Import Room Groups */ void importRoomGroups(File base) throws Exception { log.info("Room import complete, starting room groups import"); Class<RoomGroup> eClazz = RoomGroup.class; JAXBContext jc = JAXBContext.newInstance(eClazz); Unmarshaller unmarshaller = jc.createUnmarshaller(); unmarshaller.setAdapter(new RoomAdapter(roomDao, roomMap)); unmarshaller.setAdapter(new GroupAdapter(groupDao, groupMap)); readList(unmarshaller, base, "rooms_organisation.xml", ROOM_GRP_LIST_NODE, ROOM_GRP_NODE, eClazz, rg -> { if (rg.getRoom() == null || rg.getGroup() == null) { return; } Room r = roomDao.get(rg.getRoom().getId()); if (r == null || rg.getGroup().getId() == null) { return; } if (r.getGroups() == null) { r.setGroups(new ArrayList<>()); } rg.setId(null); rg.setRoom(r); r.getGroups().add(rg); roomDao.update(r, null); }); } /* * ##################### Import Chat messages */ void importChat(File base) throws Exception { log.info("Room groups import complete, starting chat messages import"); Class<ChatMessage> eClazz = ChatMessage.class; JAXBContext jc = JAXBContext.newInstance(eClazz); Unmarshaller unmarshaller = jc.createUnmarshaller(); unmarshaller.setAdapter(new UserAdapter(userDao, userMap)); unmarshaller.setAdapter(new RoomAdapter(roomDao, roomMap)); readList(unmarshaller, base, "chat_messages.xml", CHAT_LIST_NODE, CHAT_NODE, eClazz, m -> { m.setId(null); if (m.getFromUser() == null || m.getFromUser().getId() == null || (m.getToRoom() != null && m.getToRoom().getId() == null) || (m.getToUser() != null && m.getToUser().getId() == null)) { return; } chatDao.update(m, m.getSent()); }); } /* * ##################### Import Calendars */ void importCalendars(File base) throws Exception { log.info("Chat messages import complete, starting calendar import"); Class<OmCalendar> eClazz = OmCalendar.class; JAXBContext jc = JAXBContext.newInstance(eClazz); Unmarshaller unmarshaller = jc.createUnmarshaller(); unmarshaller.setAdapter(new UserAdapter(userDao, userMap)); readList(unmarshaller, base, "calendars.xml", CALENDAR_LIST_NODE, CALENDAR_NODE, eClazz, c -> { Long id = c.getId(); c.setId(null); c = calendarDao.update(c); calendarMap.put(id, c.getId()); }, true); } /* * ##################### Import Appointments */ void importAppointments(File base) throws Exception { log.info("Calendar import complete, starting appointement import"); Class<Appointment> eClazz = Appointment.class; JAXBContext jc = JAXBContext.newInstance(eClazz); Unmarshaller unmarshaller = jc.createUnmarshaller(); unmarshaller.setAdapter(new UserAdapter(userDao, userMap)); unmarshaller.setAdapter(new RoomAdapter(roomDao, roomMap)); unmarshaller.setAdapter(new OmCalendarAdapter(calendarDao, calendarMap)); readList(unmarshaller, base, "appointements.xml", APPOINTMENT_LIST_NODE, APPOINTMENT_NODE, eClazz, a -> { Long appId = a.getId(); // We need to reset this as openJPA reject to store them otherwise a.setId(null); if (a.getOwner() != null && a.getOwner().getId() == null) { a.setOwner(null); } if (a.getRoom() == null || a.getRoom().getId() == null) { log.warn("Appointment without room was found, skipping: {}", a); return; } if (a.getStart() == null || a.getEnd() == null) { log.warn("Appointment without start/end time was found, skipping: {}", a); return; } a = appointmentDao.update(a, null, false); appointmentMap.put(appId, a.getId()); }); } /* * ##################### Import MeetingMembers * * Reminder Invitations will be NOT send! */ void importMeetingMembers(File base) throws Exception { log.info("Appointement import complete, starting meeting members import"); Class<MeetingMember> eClazz = MeetingMember.class; JAXBContext jc = JAXBContext.newInstance(eClazz); Unmarshaller unmarshaller = jc.createUnmarshaller(); unmarshaller.setAdapter(new UserAdapter(userDao, userMap)); unmarshaller.setAdapter(new AppointmentAdapter(appointmentDao, appointmentMap)); readList(unmarshaller, base, "meetingmembers.xml", MMEMBER_LIST_NODE, MMEMBER_NODE, eClazz, ma -> { ma.setId(null); meetingMemberDao.update(ma); }); } private boolean isInvalidFile(BaseFileItem file, final Map<Long, Long> folders) { if (file.isDeleted()) { return true; } if (file.getParentId() != null && file.getParentId() > 0) { Long newFolder = folders.get(file.getParentId()); if (newFolder == null) { //folder was deleted return true; } else { file.setParentId(newFolder); } } else { file.setParentId(null); } if (file.getRoomId() != null) { Long newRoomId = roomMap.get(file.getRoomId()); if (newRoomId == null) { return true; // room was deleted } file.setRoomId(newRoomId); } if (file.getOwnerId() != null) { Long newOwnerId = userMap.get(file.getOwnerId()); if (newOwnerId == null) { return true; // owner was deleted } file.setOwnerId(newOwnerId); } return false; } private <T extends BaseFileItem> void saveTree( File baseDir , String fileName , String listNodeName , String nodeName , Class<T> clazz , Map<Long, Long> folders , Consumer<T> save ) { TreeMap<Long, T> items = new TreeMap<>(); readList(baseDir, fileName, listNodeName, nodeName, clazz, f -> { items.put(f.getId(), f); }, false); FileTree<T> tree = new FileTree<>(); TreeMap<Long, T> remain = new TreeMap<>(); int counter = items.size(); //max iterations while (counter > 0 && !items.isEmpty()) { Entry<Long, T> e = items.pollFirstEntry(); if (e == null) { break; } else { if (!tree.add(e.getValue())) { remain.put(e.getKey(), e.getValue()); } } if (items.isEmpty()) { counter = Math.min(counter - 1, remain.size()); items.putAll(remain); remain.clear(); } } remain.entrySet().forEach(e -> log.warn("Doungling file/recording: {}", e.getValue())); tree.process(f -> isInvalidFile(f, folders), save); } /* * ##################### Import Recordings */ void importRecordings(File base) throws Exception { log.info("Meeting members import complete, starting recordings server import"); final Map<Long, Long> folders = new HashMap<>(); saveTree(base, "flvRecordings.xml", RECORDING_LIST_NODE, RECORDING_NODE, Recording.class, folders, r -> { Long recId = r.getId(); r.setId(null); if (r.getChunks() != null) { for (RecordingChunk chunk : r.getChunks()) { chunk.setId(null); chunk.setRecording(r); } } checkHash(r, recordingDao, (oldHash, newHash) -> { if (!Strings.isEmpty(oldHash) && oldHash.startsWith(RECORDING_FILE_NAME)) { String name = getFileName(oldHash); fileMap.put(String.format(FILE_NAME_FMT, name, EXTENSION_JPG), String.format(FILE_NAME_FMT, newHash, EXTENSION_PNG)); fileMap.put(String.format("%s.%s.%s", name, "flv", EXTENSION_MP4), String.format(FILE_NAME_FMT, newHash, EXTENSION_MP4)); } }); r = recordingDao.update(r); if (BaseFileItem.Type.FOLDER == r.getType()) { folders.put(recId, r.getId()); } fileItemMap.put(recId, r.getId()); }); } private void checkHash(BaseFileItem file, BaseFileItemDao dao, BiConsumer<String, String> consumer) { String oldHash = file.getHash(); if (Strings.isEmpty(oldHash) || !UUID_PATTERN.matcher(oldHash).matches() || dao.get(oldHash) != null) { file.setHash(randomUUID().toString()); hashMap.put(oldHash, file.getHash()); if (consumer != null) { consumer.accept(oldHash, file.getHash()); } } else { hashMap.put(file.getHash(), file.getHash()); } } /* * ##################### Import Private Message Folders */ void importPrivateMsgFolders(File base) { log.info("Recording import complete, starting private message folder import"); readList(base, "privateMessageFolder.xml", MSG_FOLDER_LIST_NODE, MSG_FOLDER_NODE, PrivateMessageFolder.class, p -> { Long folderId = p.getId(); PrivateMessageFolder storedFolder = privateMessageFolderDao.get(folderId); if (storedFolder == null) { p.setId(null); Long newFolderId = privateMessageFolderDao.addPrivateMessageFolderObj(p); messageFolderMap.put(folderId, newFolderId); } }); } /* * ##################### Import User Contacts */ private void importContacts(File base) throws Exception { log.info("Private message folder import complete, starting user contacts import"); Class<UserContact> eClazz = UserContact.class; JAXBContext jc = JAXBContext.newInstance(eClazz); Unmarshaller unmarshaller = jc.createUnmarshaller(); unmarshaller.setAdapter(new UserAdapter(userDao, userMap)); readList(unmarshaller, base, "userContacts.xml", CONTACT_LIST_NODE, CONTACT_NODE, eClazz, uc -> { Long ucId = uc.getId(); UserContact storedUC = userContactDao.get(ucId); if (storedUC == null && uc.getContact() != null && uc.getContact().getId() != null) { uc.setId(null); if (uc.getOwner() != null && uc.getOwner().getId() == null) { uc.setOwner(null); } uc = userContactDao.update(uc); userContactMap.put(ucId, uc.getId()); } }); } /* * ##################### Import Private Messages */ private void importPrivateMsgs(File base) throws Exception { log.info("Usercontact import complete, starting private messages item import"); Class<PrivateMessage> eClazz = PrivateMessage.class; JAXBContext jc = JAXBContext.newInstance(eClazz); Unmarshaller unmarshaller = jc.createUnmarshaller(); unmarshaller.setAdapter(new UserAdapter(userDao, userMap)); unmarshaller.setAdapter(new RoomAdapter(roomDao, roomMap)); readList(unmarshaller, base, "privateMessages.xml", MSG_LIST_NODE, MSG_NODE, eClazz, p -> { p.setId(null); p.setFolderId(messageFolderMap.get(p.getFolderId())); p.setUserContactId(userContactMap.get(p.getUserContactId())); if (p.getRoom() != null && p.getRoom().getId() == null) { p.setRoom(null); } if (p.getTo() != null && p.getTo().getId() == null) { p.setTo(null); } if (p.getFrom() != null && p.getFrom().getId() == null) { p.setFrom(null); } if (p.getOwner() != null && p.getOwner().getId() == null) { p.setOwner(null); } privateMessageDao.update(p, null); }); } /* * ##################### Import File-Explorer Items */ private List<FileItem> importFiles(File base) throws Exception { log.info("Private message import complete, starting file explorer item import"); List<FileItem> result = new ArrayList<>(); final Map<Long, Long> folders = new HashMap<>(); saveTree(base, "fileExplorerItems.xml", FILE_LIST_NODE, FILE_NODE, FileItem.class, folders, file -> { Long fId = file.getId(); // We need to reset this as openJPA reject to store them otherwise file.setId(null); checkHash(file, fileItemDao, null); file = fileItemDao.update(file); if (BaseFileItem.Type.FOLDER == file.getType()) { folders.put(fId, file.getId()); } result.add(file); fileItemMap.put(fId, file.getId()); }); return result; } /* * ##################### Import Room Polls */ private void importPolls(File base) throws Exception { log.info("File explorer item import complete, starting room poll import"); Class<RoomPoll> eClazz = RoomPoll.class; JAXBContext jc = JAXBContext.newInstance(eClazz); Unmarshaller unmarshaller = jc.createUnmarshaller(); unmarshaller.setAdapter(new UserAdapter(userDao, userMap)); unmarshaller.setAdapter(new RoomAdapter(roomDao, roomMap)); readList(unmarshaller, base, "roompolls.xml", POLL_LIST_NODE, POLL_NODE, eClazz, rp -> { rp.setId(null); if (rp.getRoom() == null || rp.getRoom().getId() == null) { //room was deleted return; } if (rp.getCreator() == null || rp.getCreator().getId() == null) { rp.setCreator(null); } for (RoomPollAnswer rpa : rp.getAnswers()) { if (rpa.getVotedUser() == null || rpa.getVotedUser().getId() == null) { rpa.setVotedUser(null); } } pollDao.update(rp); }); } /* * ##################### Import Room Files */ private void importRoomFiles(File base) throws Exception { log.info("Poll import complete, starting room files import"); Class<RoomFile> eClazz = RoomFile.class; JAXBContext jc = JAXBContext.newInstance(eClazz); Unmarshaller unmarshaller = jc.createUnmarshaller(); unmarshaller.setAdapter(new FileAdapter(fileItemDao, fileItemMap)); readList(unmarshaller, base, "roomFiles.xml", ROOM_FILE_LIST_NODE, ROOM_FILE_NODE, eClazz, rf -> { Room r = roomDao.get(roomMap.get(rf.getRoomId())); if (r == null || rf.getFile() == null || rf.getFile().getId() == null) { return; } if (r.getFiles() == null) { r.setFiles(new ArrayList<>()); } rf.setId(null); rf.setRoomId(r.getId()); r.getFiles().add(rf); roomDao.update(r, null); }, true); } private static <T> void readList(File baseDir, String fileName, String listNodeName, String nodeName, Class<T> clazz, Consumer<T> consumer) { readList(baseDir, fileName, listNodeName, nodeName, clazz, consumer, false); } private static <T> void readList(Unmarshaller unmarshaller, File baseDir, String fileName, String listNodeName, String nodeName, Class<T> clazz, Consumer<T> consumer) { readList(unmarshaller, baseDir, fileName, listNodeName, nodeName, clazz, consumer, false); } private static <T> void readList(File baseDir, String fileName, String listNodeName, String nodeName, Class<T> clazz, Consumer<T> consumer, boolean notThow) { readList(null, baseDir, fileName, listNodeName, nodeName, clazz, consumer, notThow); } private static <T> void readList(Unmarshaller inUnmarshaller, File baseDir, String fileName, String listNodeName, String nodeName, Class<T> clazz, Consumer<T> consumer, boolean notThow) { File xml = new File(baseDir, fileName); if (!xml.exists()) { final String msg = fileName + " missing"; if (notThow) { log.debug(msg); return; } else { throw new BackupException(msg); } } try { Unmarshaller unmarshaller = inUnmarshaller; if (inUnmarshaller == null) { JAXBContext jc = JAXBContext.newInstance(clazz); unmarshaller = jc.createUnmarshaller(); } XMLInputFactory xif = XmlHelper.createInputFactory(); StreamSource xmlSource = new StreamSource(xml); XMLStreamReader xsr = xif.createXMLStreamReader(xmlSource); boolean listNodeFound = false; while (xsr.getEventType() != XMLStreamReader.END_DOCUMENT) { if (xsr.isStartElement()) { if (!listNodeFound && listNodeName.equals(xsr.getLocalName())) { listNodeFound = true; } else if (nodeName.equals(xsr.getLocalName())) { T o = unmarshaller.unmarshal(xsr, clazz).getValue(); consumer.accept(o); } } xsr.next(); } } catch (Exception e) { throw new BackupException(e); } } private static Long getPrefixedId(String prefix, File f, Map<Long, Long> map) { String n = getFileName(f.getName()); Long id = null; if (n.indexOf(prefix) > -1) { id = importLongType(n.substring(prefix.length(), n.length())); } return id == null ? null : map.get(id); } private void processGroupFiles(File baseDir) throws IOException { log.debug("Entered group logo folder"); for (File f : baseDir.listFiles()) { String ext = getFileExt(f.getName()); if (EXTENSION_PNG.equals(ext)) { Long id = getPrefixedId(GROUP_LOGO_PREFIX, f, groupMap); if (id != null) { FileUtils.copyFile(f, getGroupLogo(id, false)); } } else if (EXTENSION_CSS.equals(ext)) { Long id = getPrefixedId(GROUP_CSS_PREFIX, f, groupMap); if (id != null) { FileUtils.copyFile(f, getGroupCss(id, false)); } } } } private static void changeHash(File f, File dir, String hash, String inExt) throws IOException { String ext = inExt == null ? getFileExt(f.getName()) : inExt; FileUtils.copyFile(f, new File(dir, getName(hash, ext))); } private void processFiles(File baseDir) throws IOException { log.debug("Entered FILES folder"); for (File rf : baseDir.listFiles()) { String oldHash = OmFileHelper.getFileName(rf.getName()); String hash = hashMap.get(oldHash); if (hash == null) { continue; } File dir = new File(getUploadFilesDir(), hash); // going to fix images if (rf.isFile() && rf.getName().endsWith(EXTENSION_JPG)) { changeHash(rf, dir, hash, EXTENSION_JPG); } else { for (File f : rf.listFiles()) { FileUtils.copyFile(f, new File(dir , f.getName().startsWith(oldHash) ? getName(hash, getFileExt(f.getName())) : f.getName())); } } } } private void processProfiles(File baseDir) throws IOException { log.debug("Entered profiles folder"); for (File profile : baseDir.listFiles()) { Long id = getPrefixedId(PROFILES_PREFIX, profile, userMap); if (id != null) { FileUtils.copyDirectory(profile, getUploadProfilesUserDir(id)); } } } private void processWmls(File baseDir) throws IOException { log.debug("Entered WML folder"); File dir = getUploadWmlDir(); for (File wml : baseDir.listFiles()) { String oldHash = OmFileHelper.getFileName(wml.getName()); String hash = hashMap.get(oldHash); if (hash == null) { continue; } changeHash(wml, dir, hash, null); } } private void processFilesRoot(File baseDir) throws IOException { // Now check the room files and import them final File roomFilesFolder = new File(baseDir, BCKP_ROOM_FILES); log.debug("roomFilesFolder PATH {} ", roomFilesFolder.getCanonicalPath()); if (!roomFilesFolder.exists()) { return; } for (File file : roomFilesFolder.listFiles()) { if (file.isDirectory()) { String fName = file.getName(); if (PROFILES_DIR.equals(fName)) { processProfiles(file); } else if (FILES_DIR.equals(fName)) { processFiles(file); } else if (GROUP_LOGO_DIR.equals(fName)) { processGroupFiles(file); } else if (WML_DIR.equals(fName)) { processWmls(file); } } } } private void importFolders(File baseDir) throws IOException { processFilesRoot(baseDir); // Now check the recordings and import them final File recDir = new File(baseDir, BCKP_RECORD_FILES); log.debug("sourceDirRec PATH {}", recDir.getCanonicalPath()); if (recDir.exists()) { final File hiberDir = getStreamsHibernateDir(); for (File r : recDir.listFiles()) { String n = fileMap.get(r.getName()); if (n != null) { FileUtils.copyFile(r, new File(hiberDir, n)); } else { String oldHash = OmFileHelper.getFileName(r.getName()); String hash = hashMap.get(oldHash); if (hash == null) { FileUtils.copyFileToDirectory(r, hiberDir); } else { changeHash(r, hiberDir, hash, null); } } } } final File cssDir = new File(baseDir, CSS_DIR); if (cssDir.exists()) { final File wCssDir = getCssDir(); for (File css : cssDir.listFiles()) { FileUtils.copyFileToDirectory(css, wCssDir); } } } private static Long importLongType(String value) { Long val = null; try { val = Long.valueOf(value); } catch (Exception e) { // no-op } return val; } private void convertOldPresentation(FileItem fi) { File f = fi.getOriginal(); if (f != null && f.exists()) { try { StoredFile sf = new StoredFile(fi.getHash(), getFileExt(f.getName()), f); docConverter.convertPDF(fi, sf); } catch (Exception e) { log.error("Unexpected exception while converting OLD format presentations", e); } } } private static class UserKey { private final String login; private final User.Type type; private final Long domainId; UserKey(User u) { this.login = u.getLogin(); this.type = u.getType(); this.domainId = u.getDomainId(); } @Override public int hashCode() { return Objects.hash(domainId, login, type); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } UserKey other = (UserKey) obj; return Objects.equals(domainId, other.domainId) && Objects.equals(login, other.login) && type == other.type; } } }