/* * JBoss, Home of Professional Open Source. * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. Some portions may be licensed * to Red Hat, Inc. under one or more contributor license agreements. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. */ package org.teiid.jdbc; import java.sql.Driver; import java.sql.DriverManager; import java.sql.DriverPropertyInfo; import java.sql.SQLException; import java.util.Enumeration; import java.util.LinkedList; import java.util.List; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; import org.teiid.core.util.ApplicationInfo; import org.teiid.core.util.PropertiesUtils; import org.teiid.jdbc.JDBCURL.ConnectionType; import org.teiid.net.TeiidURL; /** * JDBC Driver class for Teiid Embedded and Teiid Server. This class automatically registers with the * {@link DriverManager} * * The accepted URL format for the connection * <ul> * <li> Server/socket connection:<b> jdbc:teiid:<vdb-name>@mm[s]://<server-name>:<port>;[user=<user-name>][password=<user-password>][other-properties]*</b> * <li> Embedded connection:<b> jdbc:teiid:<vdb-name>@<file-path-to-deploy.properties>;[user=<user-name>][password=<user-password>][other-properties]*</b> * </ul> * The user, password properties are needed if the user authentication is turned on. All the "other-properties" are simple name value pairs. * Look at {@link JDBCURL} KNOWN_PROPERTIES for list of known properties allowed. */ public class TeiidDriver implements Driver { static Logger logger = Logger.getLogger("org.teiid.jdbc"); //$NON-NLS-1$ static final String DRIVER_NAME = "Teiid JDBC Driver"; //$NON-NLS-1$ private static TeiidDriver INSTANCE = new TeiidDriver(); static { try { DriverManager.registerDriver(INSTANCE); } catch(SQLException e) { // Logging String logMsg = JDBCPlugin.Util.getString("MMDriver.Err_registering", e.getMessage()); //$NON-NLS-1$ logger.log(Level.SEVERE, logMsg); } } private ConnectionProfile socketProfile = new SocketProfile(); private ConnectionProfile localProfile; public static TeiidDriver getInstance() { return INSTANCE; } public ConnectionImpl connect(String url, Properties info) throws SQLException { ConnectionType conn = JDBCURL.acceptsUrl(url); if (conn == null) { return null; } if(info == null) { // create a properties obj if it is null info = new Properties(); } else { //don't modify the original info = PropertiesUtils.clone(info); } parseURL(url, info); ConnectionImpl myConnection = null; try { if (conn == ConnectionType.Embedded) { if (localProfile == null) { try { getClass().getClassLoader().loadClass("org.jboss.modules.Module"); //$NON-NLS-1$ } catch(ClassNotFoundException e) { throw new TeiidSQLException(JDBCPlugin.Util.gs("module_load_failed")); //$NON-NLS-1$ } localProfile = new LocalProfile(); } myConnection = localProfile.connect(url, info); } else { myConnection = socketProfile.connect(url, info); } } catch (TeiidSQLException e) { logger.log(Level.FINE, "Could not create connection", e); //$NON-NLS-1$ throw TeiidSQLException.create(e, e.getMessage()); } // logging String logMsg = JDBCPlugin.Util.getString("JDBCDriver.Connection_sucess"); //$NON-NLS-1$ logger.fine(logMsg); return myConnection; } public void setLocalProfile(ConnectionProfile embeddedProfile) { this.localProfile = embeddedProfile; } public void setSocketProfile(ConnectionProfile socketProfile) { this.socketProfile = socketProfile; } /** * Returns true if the driver thinks that it can open a connection to the given URL. * Expected URL format for server mode is * jdbc:teiid::VDB@mm://server:port;version=1;user=username;password=password * * @param The URL used to establish a connection. * @return A boolean value indicating whether the driver understands the subprotocol. * @throws SQLException, should never occur */ public boolean acceptsURL(String url) throws SQLException { return JDBCURL.acceptsUrl(url) != null; } public int getMajorVersion() { return ApplicationInfo.getInstance().getMajorReleaseVersion(); } public int getMinorVersion() { return ApplicationInfo.getInstance().getMinorReleaseVersion(); } public String getDriverName() { return DRIVER_NAME; } public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { if(info == null) { info = new Properties(); } else { info = PropertiesUtils.clone(info); } // construct list of driverPropertyInfo objects List<DriverPropertyInfo> driverProps = new LinkedList<DriverPropertyInfo>(); parseURL(url, info); for (String property: JDBCURL.KNOWN_PROPERTIES.keySet()) { DriverPropertyInfo dpi = new DriverPropertyInfo(property, info.getProperty(property)); if (property.equals(BaseDataSource.VDB_NAME)) { dpi.required = true; } driverProps.add(dpi); } // create an array of DriverPropertyInfo objects DriverPropertyInfo [] propInfo = new DriverPropertyInfo[driverProps.size()]; // copy the elements from the list to the array return driverProps.toArray(propInfo); } /** * This method parses the URL and adds properties to the the properties object. * These include required and any optional properties specified in the URL. * @param The URL needed to be parsed. * @param The properties object which is to be updated with properties in the URL. * @throws SQLException if the URL is not in the expected format. */ protected static void parseURL(String url, Properties info) throws SQLException { if(url == null) { String msg = JDBCPlugin.Util.getString("MMDriver.urlFormat"); //$NON-NLS-1$ throw new TeiidSQLException(msg); } try { JDBCURL jdbcURL = new JDBCURL(url); info.setProperty(BaseDataSource.VDB_NAME, jdbcURL.getVDBName()); if (jdbcURL.getConnectionURL() != null) { info.setProperty(TeiidURL.CONNECTION.SERVER_URL, jdbcURL.getConnectionURL()); } Properties optionalParams = jdbcURL.getProperties(); JDBCURL.normalizeProperties(info); Enumeration<?> keys = optionalParams.keys(); while (keys.hasMoreElements()) { String propName = (String)keys.nextElement(); // Don't let the URL properties override the passed-in Properties object. if (!info.containsKey(propName)) { info.setProperty(propName, optionalParams.getProperty(propName)); } } // add the property only if it is new because they could have // already been specified either through url or otherwise. if(!info.containsKey(BaseDataSource.VDB_VERSION) && jdbcURL.getVDBVersion() != null) { info.setProperty(BaseDataSource.VDB_VERSION, jdbcURL.getVDBVersion()); } if(!info.containsKey(BaseDataSource.APP_NAME)) { info.setProperty(BaseDataSource.APP_NAME, BaseDataSource.DEFAULT_APP_NAME); } } catch(IllegalArgumentException iae) { throw new TeiidSQLException(JDBCPlugin.Util.getString("MMDriver.urlFormat")); //$NON-NLS-1$ } } /** * This method returns true if the driver passes jdbc compliance tests. * @return true if the driver is jdbc complaint, else false. */ public boolean jdbcCompliant() { return false; } public Logger getParentLogger() { return logger; } }