001/* 002// This software is subject to the terms of the Eclipse Public License v1.0 003// Agreement, available at the following URL: 004// http://www.eclipse.org/legal/epl-v10.html. 005// You must accept the terms of that agreement to use this software. 006// 007// Copyright (C) 2007-2013 Pentaho 008// All Rights Reserved. 009*/ 010package mondrian.olap4j; 011 012import mondrian.rolap.RolapConnectionProperties; 013 014import java.sql.*; 015import java.util.*; 016import java.util.logging.Logger; 017 018/** 019 * Olap4j driver for Mondrian. 020 * 021 * <p>Since olap4j is a superset of JDBC, you register this driver as you would 022 * any JDBC driver: 023 * 024 * <blockquote> 025 * <code>Class.forName("mondrian.olap4j.MondrianOlap4jDriver");</code> 026 * </blockquote> 027 * 028 * <p>Then create a connection using a URL with the prefix "jdbc:mondrian:". 029 * For example, 030 * 031 * <blockquote> 032 * <code>import java.sql.Connection;<br/> 033 * import java.sql.DriverManager;<br/> 034 * import org.olap4j.OlapConnection;<br/> 035 * <br/> 036 * Connection connection =<br/> 037 * DriverManager.getConnection(<br/> 038 * "jdbc:mondrian:Jdbc=jdbc:odbc:MondrianFoodMart; 039 * Catalog=file:/mondrian/demo/FoodMart.xml; 040 * JdbcDrivers=sun.jdbc.odbc.JdbcOdbcDriver");<br/> 041 * OlapConnection olapConnection =<br/> 042 * connection.unwrap(OlapConnection.class);</code> 043 * </blockquote> 044 * 045 * <p>Note how we use the {@link Connection#unwrap(Class)} method to down-cast 046 * the JDBC connection object to the extension {@link org.olap4j.OlapConnection} 047 * object. This method is only available in the JDBC 4.0 (JDK 1.6 onwards). 048 * 049 * <h3>Connection properties</h3> 050 * 051 * <p>The driver supports the same set of properties as a traditional mondrian 052 * connection. See {@link mondrian.rolap.RolapConnectionProperties}. 053 * 054 * <h3>Catalogs and schemas</h3> 055 * 056 * <p>Mondrian has a sole catalog, called "LOCALDB". You will get an error 057 * if you attempt to use {@link java.sql.Connection#setCatalog(String)} to set 058 * it to anything else. 059 * 060 * @author jhyde 061 * @since May 22, 2007 062 */ 063public class MondrianOlap4jDriver implements Driver { 064 protected final Factory factory; 065 066 static { 067 try { 068 register(); 069 } catch (SQLException e) { 070 e.printStackTrace(); 071 } 072 } 073 074 /** 075 * Creates a MondrianOlap4jDriver. 076 */ 077 public MondrianOlap4jDriver() { 078 this.factory = createFactory(); 079 } 080 081 private static Factory createFactory() { 082 final String factoryClassName = getFactoryClassName(); 083 try { 084 // Cannot use ClassResolver here, because factory's constructor has 085 // package access. 086 final Class<?> clazz = Class.forName(factoryClassName); 087 return (Factory) clazz.newInstance(); 088 } catch (ClassNotFoundException e) { 089 throw new RuntimeException(e); 090 } catch (IllegalAccessException e) { 091 throw new RuntimeException(e); 092 } catch (InstantiationException e) { 093 throw new RuntimeException(e); 094 } 095 } 096 097 private static String getFactoryClassName() { 098 try { 099 // If java.sql.PseudoColumnUsage is present, we are running JDBC 4.1 100 // or later. 101 Class.forName("java.sql.PseudoColumnUsage"); 102 return "mondrian.olap4j.FactoryJdbc41Impl"; 103 } catch (ClassNotFoundException e) { 104 // java.sql.PseudoColumnUsage is not present. This means we are 105 // running JDBC 4.0 or earlier. 106 try { 107 Class.forName("java.sql.Wrapper"); 108 return "mondrian.olap4j.FactoryJdbc4Impl"; 109 } catch (ClassNotFoundException e2) { 110 // java.sql.Wrapper is not present. This means we are running 111 // JDBC 3.0 or earlier (probably JDK 1.5). Load the JDBC 3.0 112 // factory. 113 return "mondrian.olap4j.FactoryJdbc3Impl"; 114 } 115 } 116 } 117 118 /** 119 * Registers an instance of MondrianOlap4jDriver. 120 * 121 * <p>Called implicitly on class load, and implements the traditional 122 * 'Class.forName' way of registering JDBC drivers. 123 * 124 * @throws SQLException on error 125 */ 126 private static void register() throws SQLException { 127 DriverManager.registerDriver(new MondrianOlap4jDriver()); 128 } 129 130 public Connection connect(String url, Properties info) throws SQLException { 131 if (!MondrianOlap4jConnection.acceptsURL(url)) { 132 return null; 133 } 134 return factory.newConnection(this, url, info); 135 } 136 137 public boolean acceptsURL(String url) throws SQLException { 138 return MondrianOlap4jConnection.acceptsURL(url); 139 } 140 141 public DriverPropertyInfo[] getPropertyInfo( 142 String url, Properties info) throws SQLException 143 { 144 List<DriverPropertyInfo> list = new ArrayList<DriverPropertyInfo>(); 145 146 // First, add the contents of info 147 for (Map.Entry<Object, Object> entry : info.entrySet()) { 148 list.add( 149 new DriverPropertyInfo( 150 (String) entry.getKey(), 151 (String) entry.getValue())); 152 } 153 // Next, add property defns not mentioned in info 154 for (RolapConnectionProperties p : RolapConnectionProperties.values()) { 155 if (info.containsKey(p.name())) { 156 continue; 157 } 158 list.add( 159 new DriverPropertyInfo( 160 p.name(), 161 null)); 162 } 163 return list.toArray(new DriverPropertyInfo[list.size()]); 164 } 165 166 // JDBC 4.1 support (JDK 1.7 and higher) 167 public Logger getParentLogger() { 168 return Logger.getLogger(""); 169 } 170 171 /** 172 * Returns the driver name. Not in the JDBC API. 173 * @return Driver name 174 */ 175 String getName() { 176 return MondrianOlap4jDriverVersion.NAME; 177 } 178 179 /** 180 * Returns the driver version. Not in the JDBC API. 181 * @return Driver version 182 */ 183 String getVersion() { 184 return MondrianOlap4jDriverVersion.VERSION; 185 } 186 187 public int getMajorVersion() { 188 return MondrianOlap4jDriverVersion.MAJOR_VERSION; 189 } 190 191 public int getMinorVersion() { 192 return MondrianOlap4jDriverVersion.MINOR_VERSION; 193 } 194 195 public boolean jdbcCompliant() { 196 return false; 197 } 198} 199 200// End MondrianOlap4jDriver.java