Java tutorial
/* * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * Copyright (c) 2007 - 2017 Hitachi Vantara.. All rights reserved. */ package org.pentaho.reporting.ui.datasources.jdbc.connection; import java.util.Iterator; import java.util.Map; import java.util.Properties; import java.util.TreeMap; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.pentaho.reporting.libraries.base.util.StringUtils; /** * Manages the list of local database connections for this application. * <p/> * The list of local connections is contained in the user preferences for this user. The structure of the preferences is * as follows: * <ul> * <li>One node per connection - the name of the node is the JNDI Connection name * <li>Under each node, the following set of string keys and values which define each connection * <ul> * <li>driver - the JDBC driver class * <li>url - the URL of the database * <li>username - the username used to connect to the database * <li>password - the password used to connect to the database * </ul> * </ul> */ public class JdbcConnectionDefinitionManager { // Logger private static final Log log = LogFactory.getLog(JdbcConnectionDefinitionManager.class); // The default connection (used if no other connections can be loaded) private static final JdbcConnectionDefinition SAMPLE_DATA_JNDI_SOURCE = new JndiConnectionDefinition( "SampleData", "SampleData", "Hypersonic", null, null); private static final JdbcConnectionDefinition SAMPLE_DATA_DRIVER_SOURCE = new DriverConnectionDefinition( "SampleData (Hypersonic)", "org.hsqldb.jdbcDriver", "jdbc:hsqldb:hsql://localhost:9001/sampledata", "pentaho_user", "password"); private static final JdbcConnectionDefinition SAMPLE_DATA_MEMORY_SOURCE = new DriverConnectionDefinition( "SampleData (Memory)", "org.hsqldb.jdbcDriver", "jdbc:hsqldb:mem:SampleData", "pentaho_user", "password"); private static final JdbcConnectionDefinition LOCAL_SAMPLE_DATA_DRIVER_SOURCE = new DriverConnectionDefinition( "SampleData (Local)", "org.hsqldb.jdbcDriver", "jdbc:hsqldb:./resources/sampledata/sampledata", "pentaho_user", "password"); private static final JdbcConnectionDefinition MYSQL_SAMPLE_DATA_DRIVER_SOURCE = new DriverConnectionDefinition( "SampleData (MySQL)", "com.mysql.jdbc.Driver", "jdbc:mysql://localhost:3306/sampledata", "pentaho_user", "password"); // The location in the user preferences tree for the JNDI datasource settings private static final String DATASOURCE_PREFERENCES_NODE = "org/pentaho/reporting/ui/datasources/jdbc/Settings"; // The current set of Sources private TreeMap<String, JdbcConnectionDefinition> connectionDefinitions = new TreeMap<String, JdbcConnectionDefinition>(); /** * The reference to the preferences object for the datasource settings */ private final Preferences userPreferences; private static final String TYPE_KEY = "type"; // Constants use in the storage of the field information private static final String DRIVER_KEY = "driver"; private static final String URL_KEY = "url"; private static final String USERNAME_KEY = "username"; private static final String PASSWORD_KEY = "password"; private static final String HOSTNAME_KEY = "hostname"; private static final String PORT_KEY = "port"; private static final String DATABASE_TYPE_KEY = "database_type"; private static final String DATABASE_NAME_KEY = "database_name"; private static final String JNDI_LOCATION = "jndi-location"; /** * Initializes the instance by loading the database connection information from the configuration storage. */ public JdbcConnectionDefinitionManager() { this(DATASOURCE_PREFERENCES_NODE); } public JdbcConnectionDefinitionManager(final String node) { this(Preferences.userRoot().node(node), node); } /** * package-local visibility for testing purposes */ JdbcConnectionDefinitionManager(final Preferences externalPreferences, final String node) { userPreferences = externalPreferences; // Load the list of JNDI Sources try { final String[] childNodeNames = userPreferences.childrenNames(); for (int i = 0; i < childNodeNames.length; i++) { final String name = childNodeNames[i]; final Preferences p = userPreferences.node(name); final String type = p.get("type", null); if (type == null) { p.removeNode(); } else if (type.equals("local")) { final Properties props = new Properties(); if (p.nodeExists("properties")) { final Preferences preferences = p.node("properties"); final String[] strings = preferences.keys(); for (int j = 0; j < strings.length; j++) { final String string = strings[j]; final String value = preferences.get(string, null); if (value != null) { props.setProperty(string, value); } else { props.remove(string); } } } final DriverConnectionDefinition driverConnection = new DriverConnectionDefinition(name, p.get(DRIVER_KEY, null), p.get(URL_KEY, null), p.get(USERNAME_KEY, null), p.get(PASSWORD_KEY, null), p.get(HOSTNAME_KEY, null), p.get(DATABASE_NAME_KEY, null), p.get(DATABASE_TYPE_KEY, null), p.get(PORT_KEY, null), props); connectionDefinitions.put(name, driverConnection); } else if (type.equals("jndi")) { final JndiConnectionDefinition connectionDefinition = new JndiConnectionDefinition(name, p.get(JNDI_LOCATION, null), p.get(DATABASE_TYPE_KEY, null), p.get(USERNAME_KEY, null), p.get(PASSWORD_KEY, null)); connectionDefinitions.put(name, connectionDefinition); } else { p.removeNode(); } } } catch (BackingStoreException e) { // The system preferences system is not working - log this as a message and use defaults log.warn("Could not access the user prefererences while loading the " + "JNDI connection information - using default JNDI connection entries", e); } catch (final Exception e) { log.warn("Configuration information was invalid.", e); } // If the connectionDefinitions is empty, add any default entries if (connectionDefinitions.isEmpty() && DATASOURCE_PREFERENCES_NODE.equals(node)) { if (userPreferences.getBoolean("sample-data-created", false) == true) { // only create the sample connections once, if we work on a totally fresh config. return; } updateSourceList(SAMPLE_DATA_JNDI_SOURCE); updateSourceList(SAMPLE_DATA_DRIVER_SOURCE); updateSourceList(SAMPLE_DATA_MEMORY_SOURCE); updateSourceList(LOCAL_SAMPLE_DATA_DRIVER_SOURCE); updateSourceList(MYSQL_SAMPLE_DATA_DRIVER_SOURCE); userPreferences.putBoolean("sample-data-created", true); try { userPreferences.flush(); } catch (BackingStoreException e) { // ignored .. } } } /** * Returns a copy of the current list of JNDI sources */ public JdbcConnectionDefinition[] getSources() { return connectionDefinitions.values().toArray(new JdbcConnectionDefinition[connectionDefinitions.size()]); } /** * Removes the specified connection-definition from the list of connections. * * @param name * the name of the JNDI source to remove from the list */ public void removeSource(final String name) { // Make sure the name provided is not null if (StringUtils.isEmpty(name)) { throw new IllegalArgumentException("The provided name is invalid"); } // If the source is in our list, remove it connectionDefinitions.remove(name); // Remove the entry from the user preferences try { final Preferences node = userPreferences.node(name); if (node != null) { node.removeNode(); userPreferences.flush(); } } catch (BackingStoreException e) { log.error("Could not remove JNDI connection entry [" + name + ']', e); } } /** * Adds or updates the source list with the specified source entry. Delagates to JNDI or JDBC method * * @param source * the entry to add/update in the list * @throws IllegalArgumentException * indicates the source is <code>null</code> */ public boolean updateSourceList(final JdbcConnectionDefinition source) { if (source == null) { throw new IllegalArgumentException("The provided source is null"); } if (source instanceof DriverConnectionDefinition) { return updateSourceList((DriverConnectionDefinition) source); } if (source instanceof JndiConnectionDefinition) { return updateSourceList((JndiConnectionDefinition) source); } else { throw new IllegalArgumentException("The provided source is not a supported type"); } } /** * Adds or updates the source list with the specified source entry. If the entry exists (has the same name), the new * entry will replace the old entry. If the enrty does not already exist, the new entry will be added to the list. <br> * Since the definition of the ConnectionDefintion ensures that it will be valid, no testing will be performed on the * contents of the ConnectionDefintion. * * @param source * the entry to add/update in the list * @throws IllegalArgumentException * indicates the source is <code>null</code> */ private boolean updateSourceList(final DriverConnectionDefinition source) throws IllegalArgumentException { if (source == null) { throw new IllegalArgumentException("The provided source is null"); } // Update the node in the list final boolean updateExisting = (connectionDefinitions.put(source.getName(), source) != null); // Update the information in the preferences try { final Preferences node = userPreferences.node(source.getName()); put(node, TYPE_KEY, "local"); put(node, DRIVER_KEY, source.getDriverClass()); put(node, URL_KEY, source.getConnectionString()); put(node, USERNAME_KEY, source.getUsername()); put(node, PASSWORD_KEY, source.getPassword()); put(node, HOSTNAME_KEY, source.getHostName()); put(node, PORT_KEY, source.getPort()); put(node, DATABASE_TYPE_KEY, source.getDatabaseType()); put(node, DATABASE_NAME_KEY, source.getDatabaseName()); final Preferences preferences = node.node("properties"); final Properties properties = source.getProperties(); final Iterator entryIterator = properties.entrySet().iterator(); while (entryIterator.hasNext()) { final Map.Entry entry = (Map.Entry) entryIterator.next(); put(preferences, String.valueOf(entry.getKey()), String.valueOf(entry.getValue())); } node.flush(); } catch (BackingStoreException e) { log.error("Could not add/update connection entry [" + source.getName() + ']', e); } return updateExisting; } private static void put(final Preferences node, final String key, final String value) { if (value == null) { node.remove(key); } else { node.put(key, value); } } /** * Adds or updates the source list with the specified source entry. If the entry exists (has the same name), the new * entry will replace the old entry. If the enrty does not already exist, the new entry will be added to the list. <br> * Since the definition of the ConnectionDefintion ensures that it will be valid, no testing will be performed on the * contents of the ConnectionDefintion. * * @param source * the entry to add/update in the list * @throws IllegalArgumentException * indicates the source is <code>null</code> */ private boolean updateSourceList(final JndiConnectionDefinition source) throws IllegalArgumentException { if (source == null) { throw new IllegalArgumentException("The provided source is null"); } // Update the node in the list final boolean updateExisting = (connectionDefinitions.put(source.getName(), source) != null); // Update the information in the preferences try { final Preferences node = userPreferences.node(source.getName()); put(node, TYPE_KEY, "jndi"); put(node, JNDI_LOCATION, source.getJndiName()); put(node, USERNAME_KEY, null); put(node, PASSWORD_KEY, null); put(node, DATABASE_TYPE_KEY, source.getDatabaseType()); node.flush(); } catch (BackingStoreException e) { log.error("Could not add/update connection entry [" + source.getName() + ']', e); } return updateExisting; } }