/* * 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.registry; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.Platform; import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.core.DBeaverActivator; import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.connection.DBPConnectionType; import org.jkiss.dbeaver.model.app.DBPRegistryListener; import org.jkiss.dbeaver.model.connection.DBPDriver; import org.jkiss.dbeaver.registry.driver.DriverDescriptor; import org.jkiss.dbeaver.utils.GeneralUtils; import org.jkiss.utils.CommonUtils; import org.jkiss.utils.xml.SAXListener; import org.jkiss.utils.xml.SAXReader; import org.jkiss.utils.xml.XMLBuilder; import org.jkiss.utils.xml.XMLException; import org.xml.sax.Attributes; import java.io.*; import java.net.URL; import java.util.*; public class DataSourceProviderRegistry { private static final Log log = Log.getLog(DataSourceProviderRegistry.class); private static DataSourceProviderRegistry instance = null; public synchronized static DataSourceProviderRegistry getInstance() { if (instance == null) { instance = new DataSourceProviderRegistry(); instance.loadExtensions(Platform.getExtensionRegistry()); } return instance; } private final List<DataSourceProviderDescriptor> dataSourceProviders = new ArrayList<>(); private final List<DBPRegistryListener> registryListeners = new ArrayList<>(); private final Map<String, DBPConnectionType> connectionTypes = new LinkedHashMap<>(); private final Map<String, ExternalResourceDescriptor> resourceContributions = new HashMap<>(); private DataSourceProviderRegistry() { } public void loadExtensions(IExtensionRegistry registry) { // Load datasource providers from external plugins { IConfigurationElement[] extElements = registry.getConfigurationElementsFor(DataSourceProviderDescriptor.EXTENSION_ID); for (IConfigurationElement ext : extElements) { DataSourceProviderDescriptor provider = new DataSourceProviderDescriptor(this, ext); dataSourceProviders.add(provider); } Collections.sort(dataSourceProviders, new Comparator<DataSourceProviderDescriptor>() { @Override public int compare(DataSourceProviderDescriptor o1, DataSourceProviderDescriptor o2) { if (o1.isDriversManagable() && !o2.isDriversManagable()) { return 1; } if (o2.isDriversManagable() && !o1.isDriversManagable()) { return -1; } return o1.getName().compareToIgnoreCase(o2.getName()); } }); } // Load drivers File driversConfig = DBeaverActivator.getConfigurationFile(RegistryConstants.DRIVERS_FILE_NAME); if (driversConfig.exists()) { loadDrivers(driversConfig); } // Resolve all driver replacements { List<DriverDescriptor> allDrivers = new ArrayList<>(); for (DataSourceProviderDescriptor provider : dataSourceProviders) { allDrivers.addAll(provider.getDrivers()); } for (DriverDescriptor driver1 : allDrivers) { for (DriverDescriptor driver2 : allDrivers) { if (driver1 != driver2 && driver1.replaces(driver2)) { driver2.setReplacedBy(driver1); } } } } // Load connection types { for (DBPConnectionType ct : DBPConnectionType.SYSTEM_TYPES) { connectionTypes.put(ct.getId(), ct); } File ctConfig = DBeaverActivator.getConfigurationFile(RegistryConstants.CONNECTION_TYPES_FILE_NAME); if (ctConfig.exists()) { loadConnectionTypes(ctConfig); } } // Load external resources information { IConfigurationElement[] extElements = registry.getConfigurationElementsFor(ExternalResourceDescriptor.EXTENSION_ID); for (IConfigurationElement ext : extElements) { ExternalResourceDescriptor resource = new ExternalResourceDescriptor(ext); resourceContributions.put(resource.getName(), resource); } } } public void dispose() { synchronized (registryListeners) { if (!registryListeners.isEmpty()) { log.warn("Some datasource registry listeners are still registered: " + registryListeners); } registryListeners.clear(); } for (DataSourceProviderDescriptor providerDescriptor : this.dataSourceProviders) { providerDescriptor.dispose(); } this.dataSourceProviders.clear(); this.resourceContributions.clear(); } @Nullable public DataSourceProviderDescriptor getDataSourceProvider(String id) { for (DataSourceProviderDescriptor provider : dataSourceProviders) { if (provider.getId().equals(id)) { return provider; } } return null; } public List<DataSourceProviderDescriptor> getDataSourceProviders() { return dataSourceProviders; } @Nullable public DriverDescriptor findDriver(@NotNull String driverName) { // Try to find by ID for (DataSourceProviderDescriptor pd : dataSourceProviders) { DriverDescriptor driver = pd.getDriver(driverName); if (driver != null) { return driver; } } // Try to find by name for (DataSourceProviderDescriptor pd : dataSourceProviders) { for (DriverDescriptor driver : pd.getDrivers()) { if (driver.getName().equalsIgnoreCase(driverName)) { return driver; } } } return null; } private void loadDrivers(File driversConfig) { if (driversConfig.exists()) { try { try (InputStream is = new FileInputStream(driversConfig)) { new SAXReader(is).parse(new DriverDescriptor.DriversParser()); } catch (XMLException ex) { log.warn("Drivers config parse error", ex); } } catch (Exception ex) { log.warn("Error loading drivers from " + driversConfig.getPath(), ex); } } } public void saveDrivers() { File driversConfig = DBeaverActivator.getConfigurationFile(RegistryConstants.DRIVERS_FILE_NAME); try { OutputStream os = new FileOutputStream(driversConfig); XMLBuilder xml = new XMLBuilder(os, GeneralUtils.UTF8_ENCODING); xml.setButify(true); xml.startElement(RegistryConstants.TAG_DRIVERS); for (DataSourceProviderDescriptor provider : this.dataSourceProviders) { xml.startElement(RegistryConstants.TAG_PROVIDER); xml.addAttribute(RegistryConstants.ATTR_ID, provider.getId()); for (DriverDescriptor driver : provider.getDrivers()) { if (driver.isModified()) { driver.serialize(xml, false); } } xml.endElement(); } xml.endElement(); xml.flush(); os.close(); } catch (Exception ex) { log.warn("Error saving drivers", ex); } } private void loadConnectionTypes(File configFile) { try { try (InputStream is = new FileInputStream(configFile)) { new SAXReader(is).parse(new ConnectionTypeParser()); } catch (XMLException ex) { log.warn("Can't load connection types config from " + configFile.getPath(), ex); } } catch (Exception ex) { log.warn("Error parsing connection types", ex); } } public Collection<DBPConnectionType> getConnectionTypes() { return connectionTypes.values(); } public DBPConnectionType getConnectionType(String id, DBPConnectionType defaultType) { DBPConnectionType connectionType = connectionTypes.get(id); return connectionType == null ? defaultType : connectionType; } public void addConnectionType(DBPConnectionType connectionType) { if (this.connectionTypes.containsKey(connectionType.getId())) { log.warn("Duplicate connection type id: " + connectionType.getId()); return; } this.connectionTypes.put(connectionType.getId(), connectionType); } public void removeConnectionType(DBPConnectionType connectionType) { if (!this.connectionTypes.containsKey(connectionType.getId())) { log.warn("Connection type doesn't exist: " + connectionType.getId()); return; } this.connectionTypes.remove(connectionType.getId()); } public void saveConnectionTypes() { File ctConfig = DBeaverActivator.getConfigurationFile(RegistryConstants.CONNECTION_TYPES_FILE_NAME); try { OutputStream os = new FileOutputStream(ctConfig); XMLBuilder xml = new XMLBuilder(os, GeneralUtils.UTF8_ENCODING); xml.setButify(true); xml.startElement(RegistryConstants.TAG_TYPES); for (DBPConnectionType connectionType : connectionTypes.values()) { xml.startElement(RegistryConstants.TAG_TYPE); xml.addAttribute(RegistryConstants.ATTR_ID, connectionType.getId()); xml.addAttribute(RegistryConstants.ATTR_NAME, CommonUtils.toString(connectionType.getName())); xml.addAttribute(RegistryConstants.ATTR_COLOR, connectionType.getColor()); xml.addAttribute(RegistryConstants.ATTR_DESCRIPTION, CommonUtils.toString(connectionType.getDescription())); xml.addAttribute(RegistryConstants.ATTR_AUTOCOMMIT, connectionType.isAutocommit()); xml.addAttribute(RegistryConstants.ATTR_CONFIRM_EXECUTE, connectionType.isConfirmExecute()); xml.endElement(); } xml.endElement(); xml.flush(); os.close(); } catch (Exception ex) { log.warn("Error saving drivers", ex); } } /** * Searches for resource within external resources provided by plugins * @param resourcePath path * @return URL or null if specified resource not found */ @Nullable public URL findResourceURL(String resourcePath) { ExternalResourceDescriptor descriptor = resourceContributions.get(resourcePath); return descriptor == null ? null : descriptor.getURL(); } public void addDataSourceRegistryListener(DBPRegistryListener listener) { synchronized (registryListeners) { registryListeners.add(listener); } } public void removeDataSourceRegistryListener(DBPRegistryListener listener) { synchronized (registryListeners) { registryListeners.remove(listener); } } void fireRegistryChange(DataSourceRegistry registry, boolean load) { synchronized (registryListeners) { for (DBPRegistryListener listener : registryListeners) { if (load) { listener.handleRegistryLoad(registry); } else { listener.handleRegistryUnload(registry); } } } } class ConnectionTypeParser implements SAXListener { @Override public void saxStartElement(SAXReader reader, String namespaceURI, String localName, Attributes atts) throws XMLException { if (localName.equals(RegistryConstants.TAG_TYPE)) { DBPConnectionType connectionType = new DBPConnectionType( atts.getValue(RegistryConstants.ATTR_ID), atts.getValue(RegistryConstants.ATTR_NAME), atts.getValue(RegistryConstants.ATTR_COLOR), atts.getValue(RegistryConstants.ATTR_DESCRIPTION), CommonUtils.getBoolean(atts.getValue(RegistryConstants.ATTR_AUTOCOMMIT)), CommonUtils.getBoolean(atts.getValue(RegistryConstants.ATTR_CONFIRM_EXECUTE))); connectionTypes.put(connectionType.getId(), connectionType); } } @Override public void saxText(SAXReader reader, String data) {} @Override public void saxEndElement(SAXReader reader, String namespaceURI, String localName) {} } }