/* * DBeaver - Universal Database Manager * Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org) * * 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 org.jkiss.dbeaver.tools.project; import org.jkiss.dbeaver.Log; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.QualifiedName; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.wizard.Wizard; import org.eclipse.swt.SWT; import org.eclipse.ui.IImportWizard; import org.eclipse.ui.IWorkbench; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.core.CoreMessages; import org.jkiss.dbeaver.core.DBeaverCore; import org.jkiss.dbeaver.core.DBeaverUI; import org.jkiss.dbeaver.model.connection.DBPDriverLibrary; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; import org.jkiss.dbeaver.model.runtime.DBRRunnableWithProgress; import org.jkiss.dbeaver.registry.*; import org.jkiss.dbeaver.registry.driver.DriverDescriptor; import org.jkiss.dbeaver.utils.RuntimeUtils; import org.jkiss.dbeaver.ui.UIUtils; import org.jkiss.dbeaver.utils.ContentUtils; import org.jkiss.dbeaver.utils.GeneralUtils; import org.jkiss.utils.CommonUtils; import org.jkiss.utils.IOUtils; import org.jkiss.utils.xml.XMLException; import org.jkiss.utils.xml.XMLUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; import java.io.*; import java.lang.reflect.InvocationTargetException; import java.util.*; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; public class ProjectImportWizard extends Wizard implements IImportWizard { private static final Log log = Log.getLog(ProjectImportWizard.class); private ProjectImportData data = new ProjectImportData(); public ProjectImportWizard() { } @Override public void init(IWorkbench workbench, IStructuredSelection selection) { setWindowTitle(CoreMessages.dialog_project_import_wizard_title); setNeedsProgressMonitor(true); } @Override public void addPages() { super.addPages(); addPage(new ProjectImportWizardPageFile(data)); //addPage(new ProjectImportWizardPageFinal(data)); } @Override public boolean performFinish() { try { DBeaverUI.run(getContainer(), true, true, new DBRRunnableWithProgress() { @Override public void run(DBRProgressMonitor monitor) throws InvocationTargetException, InterruptedException { try { importProjects(monitor); } catch (Exception e) { throw new InvocationTargetException(e); } } }); } catch (InterruptedException ex) { return false; } catch (InvocationTargetException ex) { UIUtils.showErrorDialog( getShell(), "Import error", "Cannot import projects", ex.getTargetException()); return false; } UIUtils.showMessageBox(getShell(), CoreMessages.dialog_project_import_wizard_message_success_import_title, CoreMessages.dialog_project_import_wizard_message_success_import_message, SWT.ICON_INFORMATION); return true; } private void importProjects(DBRProgressMonitor monitor) throws IOException, DBException { try (ZipFile zipFile = new ZipFile(data.getImportFile(), ZipFile.OPEN_READ)) { ZipEntry metaEntry = zipFile.getEntry(ExportConstants.META_FILENAME); if (metaEntry == null) { throw new DBException("Cannot find meta file"); } final Map<String, String> libMap = new HashMap<>(); final Map<String, String> driverMap = new HashMap<>(); InputStream metaStream = zipFile.getInputStream(metaEntry); if (metaStream == null) { throw new DBException("Cannot open meta file '" + metaEntry.getName() + "'"); //$NON-NLS-2$ } try { final Document metaDocument = XMLUtils.parseDocument(metaStream); { // Read libraries map final Element libsElement = XMLUtils.getChildElement(metaDocument.getDocumentElement(), ExportConstants.TAG_LIBRARIES); if (libsElement != null) { final Collection<Element> libList = XMLUtils.getChildElementList(libsElement, RegistryConstants.TAG_FILE); monitor.beginTask(CoreMessages.dialog_project_import_wizard_monitor_load_libraries, libList.size()); for (Element libElement : libList) { libMap.put( libElement.getAttribute(ExportConstants.ATTR_PATH), libElement.getAttribute(ExportConstants.ATTR_FILE)); monitor.worked(1); } monitor.done(); } } { // Collect drivers to import final Element driversElement = XMLUtils.getChildElement(metaDocument.getDocumentElement(), RegistryConstants.TAG_DRIVERS); if (driversElement != null) { final Collection<Element> driverList = XMLUtils.getChildElementList(driversElement, RegistryConstants.TAG_DRIVER); monitor.beginTask(CoreMessages.dialog_project_import_wizard_monitor_import_drivers, driverList.size()); for (Element driverElement : driverList) { if (monitor.isCanceled()) { break; } importDriver(monitor, driverElement, zipFile, libMap, driverMap); monitor.worked(1); } // Save drivers DataSourceProviderRegistry.getInstance().saveDrivers(); monitor.done(); } } { // Import projects final Element projectsElement = XMLUtils.getChildElement(metaDocument.getDocumentElement(), ExportConstants.TAG_PROJECTS); if (projectsElement != null) { final Collection<Element> projectList = XMLUtils.getChildElementList(projectsElement, ExportConstants.TAG_PROJECT); monitor.beginTask(CoreMessages.dialog_project_import_wizard_monitor_import_projects, projectList.size()); for (Element projectElement : projectList) { if (monitor.isCanceled()) { break; } importProject(monitor, projectElement, zipFile, driverMap); monitor.worked(1); } monitor.done(); } } } catch (XMLException e) { throw new DBException("Cannot parse meta file", e); } catch (CoreException e) { throw new DBException("Cannot persist project", e); } finally { metaStream.close(); } } } private DriverDescriptor importDriver( DBRProgressMonitor monitor, Element driverElement, ZipFile zipFile, Map<String, String> libMap, Map<String, String> driverMap) throws IOException, DBException { String providerId = driverElement.getAttribute(RegistryConstants.ATTR_PROVIDER); String driverId = driverElement.getAttribute(RegistryConstants.ATTR_ID); boolean isCustom = CommonUtils.getBoolean(driverElement.getAttribute(RegistryConstants.ATTR_CUSTOM)); String driverCategory = driverElement.getAttribute(RegistryConstants.ATTR_CATEGORY); String driverName = driverElement.getAttribute(RegistryConstants.ATTR_NAME); String driverClass = driverElement.getAttribute(RegistryConstants.ATTR_CLASS); String driverURL = driverElement.getAttribute(RegistryConstants.ATTR_URL); String driverDefaultPort = driverElement.getAttribute(RegistryConstants.ATTR_PORT); String driverDescription = driverElement.getAttribute(RegistryConstants.ATTR_DESCRIPTION); DataSourceProviderDescriptor dataSourceProvider = DataSourceProviderRegistry.getInstance().getDataSourceProvider(providerId); if (dataSourceProvider == null) { throw new DBException("Cannot find data source provider '" + providerId + "' for driver '" + driverName + "'"); } monitor.subTask(CoreMessages.dialog_project_import_wizard_monitor_load_driver + driverName); DriverDescriptor driver = null; if (!isCustom) { // Get driver by ID driver = dataSourceProvider.getDriver(driverId); if (driver == null) { log.warn("Driver '" + driverId + "' not found in data source provider '" + dataSourceProvider.getName() + "'"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } } if (driver == null) { // Try to find existing driver by class name List<DriverDescriptor> matchedDrivers = new ArrayList<>(); for (DriverDescriptor tmpDriver : dataSourceProvider.getEnabledDrivers()) { if (tmpDriver.getDriverClassName().equals(driverClass)) { matchedDrivers.add(tmpDriver); } } if (matchedDrivers.size() == 1) { driver = matchedDrivers.get(0); } else if (!matchedDrivers.isEmpty()) { // Multiple drivers with the same class - tru to find driver with the same sample URL or with the same name for (DriverDescriptor tmpDriver : matchedDrivers) { if (CommonUtils.equalObjects(tmpDriver.getSampleURL(), driverURL) || CommonUtils.equalObjects(tmpDriver.getName(), driverName)) { driver = tmpDriver; break; } } if (driver == null) { // Not found - lets use first one log.warn("Ambiguous driver '" + driverName + "' - multiple drivers with class '" + driverClass + "' found. First one will be used"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ driver = matchedDrivers.get(0); } } } if (driver == null) { // Create new driver driver = dataSourceProvider.createDriver(); driver.setName(driverName); driver.setCategory(driverCategory); driver.setDescription(driverDescription); driver.setDriverClassName(driverClass); if (!CommonUtils.isEmpty(driverDefaultPort)) { driver.setDriverDefaultPort(driverDefaultPort); } driver.setSampleURL(driverURL); driver.setModified(true); dataSourceProvider.addDriver(driver); } // Parameters and properties for (Element libElement : XMLUtils.getChildElementList(driverElement, RegistryConstants.TAG_PARAMETER)) { driver.setDriverParameter( libElement.getAttribute(RegistryConstants.ATTR_NAME), libElement.getAttribute(RegistryConstants.ATTR_VALUE), false); } for (Element libElement : XMLUtils.getChildElementList(driverElement, RegistryConstants.TAG_PROPERTY)) { driver.setConnectionProperty( libElement.getAttribute(RegistryConstants.ATTR_NAME), libElement.getAttribute(RegistryConstants.ATTR_VALUE)); } // Add libraries (only for managable drivers with empty library list) if (CommonUtils.isEmpty(driver.getDriverLibraries())) { List<String> libraryList = new ArrayList<>(); for (Element libElement : XMLUtils.getChildElementList(driverElement, RegistryConstants.TAG_FILE)) { libraryList.add(libElement.getAttribute(RegistryConstants.ATTR_PATH)); } for (String libPath : libraryList) { File libFile = new File(libPath); if (libFile.exists()) { // Just use path as-is (may be it is local re-import or local environments equal to export environment) driver.addDriverLibrary(libPath, DBPDriverLibrary.FileType.jar); } else { // Get driver library from archive String archiveLibEntry = libMap.get(libPath); if (archiveLibEntry != null) { ZipEntry libEntry = zipFile.getEntry(archiveLibEntry); if (libEntry != null) { // Extract driver to "drivers" folder String libName = libFile.getName(); File contribFolder = DriverDescriptor.getDriversContribFolder(); if (!contribFolder.exists()) { if (!contribFolder.mkdir()) { log.error("Cannot create drivers folder '" + contribFolder.getAbsolutePath() + "'"); //$NON-NLS-1$ //$NON-NLS-2$ continue; } } File importLibFile = new File(contribFolder, libName); if (!importLibFile.exists()) { try (FileOutputStream os = new FileOutputStream(importLibFile)) { try (InputStream is = zipFile.getInputStream(libEntry)) { IOUtils.copyStream(is, os); } } } // Make relative path String contribPath = contribFolder.getAbsolutePath(); String libAbsolutePath = importLibFile.getAbsolutePath(); String relativePath = libAbsolutePath.substring(contribPath.length()); while (relativePath.charAt(0) == '/' || relativePath.charAt(0) == '\\') { relativePath = relativePath.substring(1); } driver.addDriverLibrary(relativePath, DBPDriverLibrary.FileType.jar); } } } } } // Update driver map driverMap.put(driverId, driver.getId()); return driver; } private IProject importProject(DBRProgressMonitor monitor, Element projectElement, ZipFile zipFile, Map<String, String> driverMap) throws DBException, CoreException, IOException { String projectName = projectElement.getAttribute(ExportConstants.ATTR_NAME); String projectDescription = projectElement.getAttribute(ExportConstants.ATTR_DESCRIPTION); String targetProjectName = data.getTargetProjectName(projectName); if (targetProjectName == null) { return null; } IProject project = DBeaverCore.getInstance().getWorkspace().getRoot().getProject(targetProjectName); if (project.exists()) { throw new DBException("Project '" + targetProjectName + "' already exists"); } monitor.subTask(CoreMessages.dialog_project_import_wizard_monitor_import_project + targetProjectName); final IProjectDescription description = DBeaverCore.getInstance().getWorkspace().newProjectDescription(project.getName()); if (!CommonUtils.isEmpty(projectDescription)) { description.setComment(projectDescription); } ProjectRegistry projectRegistry = DBeaverCore.getInstance().getProjectRegistry(); project.create(description, 0, RuntimeUtils.getNestedMonitor(monitor)); try { // Open project project.open(RuntimeUtils.getNestedMonitor(monitor)); // Set project properties loadResourceProperties(monitor, project, projectElement); // Load resources importChildResources( monitor, project, projectElement, ExportConstants.DIR_PROJECTS + "/" + projectName + "/", //$NON-NLS-1$ //$NON-NLS-2$ zipFile); // Update driver references in datasources updateDriverReferences(monitor, project, driverMap); } catch (Exception e) { // Cleanup project which was partially imported try { project.delete(true, true, RuntimeUtils.getNestedMonitor(monitor)); } catch (CoreException e1) { log.error(e1); } throw new DBException("Error importing project resources", e); } if (projectRegistry.getDataSourceRegistry(project) == null) { projectRegistry.addProject(project); } return project; } private void importChildResources(DBRProgressMonitor monitor, IContainer resource, Element resourceElement, String containerPath, ZipFile zipFile) throws DBException, IOException, CoreException { for (Element childElement : XMLUtils.getChildElementList(resourceElement, ExportConstants.TAG_RESOURCE)) { String childName = childElement.getAttribute(ExportConstants.ATTR_NAME); boolean isDirectory = CommonUtils.getBoolean(childElement.getAttribute(ExportConstants.ATTR_DIRECTORY)); String entryPath = containerPath + childName; if (isDirectory) { entryPath += "/"; //$NON-NLS-1$ } final ZipEntry resourceEntry = zipFile.getEntry(entryPath); if (resourceEntry == null) { throw new DBException("Project resource '" + entryPath + "' not found in archive"); } if (isDirectory != resourceEntry.isDirectory()) { throw new DBException("Directory '" + entryPath + "' stored as file in archive"); } IResource childResource; if (isDirectory) { IFolder folder; if (resource instanceof IFolder) { folder = ((IFolder)resource).getFolder(childName); } else if (resource instanceof IProject) { folder = ((IProject)resource).getFolder(childName); } else { throw new DBException("Unsupported container type '" + resource.getClass().getName() + "'"); } if (!folder.exists()) { folder.create(true, true, RuntimeUtils.getNestedMonitor(monitor)); } childResource = folder; importChildResources(monitor, folder, childElement, entryPath, zipFile); } else { IFile file; if (resource instanceof IFolder) { file = ((IFolder)resource).getFile(childName); } else if (resource instanceof IProject) { file = ((IProject)resource).getFile(childName); } else { throw new DBException("Unsupported container type '" + resource.getClass().getName() + "'"); } if (!file.exists()) { file.create(zipFile.getInputStream(resourceEntry), true, RuntimeUtils.getNestedMonitor(monitor)); } childResource = file; } loadResourceProperties(monitor, childResource, childElement); } } private void loadResourceProperties(DBRProgressMonitor monitor, IResource resource, Element element) throws CoreException, IOException { if (resource instanceof IFile) { final String charset = element.getAttribute(ExportConstants.ATTR_CHARSET); if (!CommonUtils.isEmpty(charset)) { ((IFile) resource).setCharset(charset, RuntimeUtils.getNestedMonitor(monitor)); } } for (Element attrElement : XMLUtils.getChildElementList(element, ExportConstants.TAG_ATTRIBUTE)) { String qualifier = attrElement.getAttribute(ExportConstants.ATTR_QUALIFIER); String name = attrElement.getAttribute(ExportConstants.ATTR_NAME); String value = attrElement.getAttribute(ExportConstants.ATTR_VALUE); if (!CommonUtils.isEmpty(qualifier) && !CommonUtils.isEmpty(name) && !CommonUtils.isEmpty(value)) { resource.setPersistentProperty(new QualifiedName(qualifier, name), value); } } } private void updateDriverReferences(DBRProgressMonitor monitor, IProject project, Map<String, String> driverMap) throws DBException, CoreException, IOException { IFile configFile = project.getFile(DataSourceRegistry.CONFIG_FILE_NAME); if (configFile == null || !configFile.exists()) { configFile = project.getFile(DataSourceRegistry.OLD_CONFIG_FILE_NAME); } if (configFile == null || !configFile.exists()) { throw new DBException("Cannot find configuration file '" + DataSourceRegistry.CONFIG_FILE_NAME + "'"); } // Read and filter datasources config final InputStream configContents = configFile.getContents(); String filteredContent; try { BufferedReader in = new BufferedReader(new InputStreamReader(configContents, GeneralUtils.DEFAULT_FILE_CHARSET)); StringBuilder buffer = new StringBuilder(); for (;;) { String line = in.readLine(); if (line == null) { break; } buffer.append(line).append(GeneralUtils.getDefaultLineSeparator()); } filteredContent = buffer.toString(); for (Map.Entry<String, String> entry : driverMap.entrySet()) { if (!entry.getKey().equals(entry.getValue())) { filteredContent = filteredContent.replace("driver=\"" + entry.getKey() + "\"", "driver=\"" + entry.getValue() + "\""); } } } finally { ContentUtils.close(configContents); } // Update configuration configFile.setContents( new ByteArrayInputStream(filteredContent.getBytes(GeneralUtils.DEFAULT_FILE_CHARSET)), true, false, RuntimeUtils.getNestedMonitor(monitor)); } }