001/* 002 * ModeShape (http://www.modeshape.org) 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.modeshape.jdbc; 017 018import java.sql.Array; 019import java.sql.Blob; 020import java.sql.CallableStatement; 021import java.sql.ClientInfoStatus; 022import java.sql.Clob; 023import java.sql.Connection; 024import java.sql.DatabaseMetaData; 025import java.sql.NClob; 026import java.sql.PreparedStatement; 027import java.sql.SQLClientInfoException; 028import java.sql.SQLException; 029import java.sql.SQLFeatureNotSupportedException; 030import java.sql.SQLWarning; 031import java.sql.SQLXML; 032import java.sql.Savepoint; 033import java.sql.Statement; 034import java.sql.Struct; 035import java.util.HashMap; 036import java.util.Map; 037import java.util.Properties; 038import java.util.concurrent.Executor; 039import javax.jcr.Repository; 040import javax.jcr.RepositoryException; 041import javax.jcr.nodetype.NodeType; 042import javax.jcr.query.Query; 043import org.modeshape.jdbc.delegate.ConnectionInfo; 044import org.modeshape.jdbc.delegate.RepositoryDelegate; 045 046/** 047 * This driver's implementation of JDBC {@link Connection}. 048 */ 049public class JcrConnection implements Connection { 050 051 public static final String JCR_SQL2 = Query.JCR_SQL2; 052 @SuppressWarnings( "deprecation" ) 053 public static final String JCR_SQL = Query.SQL; 054 055 private boolean closed; 056 private boolean autoCommit = true; 057 private SQLWarning warning; 058 private Properties clientInfo = new Properties(); 059 private DatabaseMetaData metadata; 060 private final RepositoryDelegate jcrDelegate; 061 private final DriverInfo driverInfo; 062 063 public JcrConnection( RepositoryDelegate jcrDelegate, 064 DriverInfo driverInfo ) { 065 this.jcrDelegate = jcrDelegate; 066 this.driverInfo = driverInfo; 067 assert this.jcrDelegate != null; 068 assert this.driverInfo != null; 069 } 070 071 protected ConnectionInfo info() { 072 return this.jcrDelegate.getConnectionInfo(); 073 } 074 075 protected DriverInfo driverInfo() { 076 return this.driverInfo; 077 } 078 079 /** 080 * Returns the interface used to communicate to the Jcr Repository. 081 * 082 * @return RepositoryDelegate 083 */ 084 public RepositoryDelegate getRepositoryDelegate() { 085 return this.jcrDelegate; 086 } 087 088 protected NodeType nodeType( String name ) throws SQLException { 089 try { 090 return getRepositoryDelegate().nodeType(name); 091 } catch (RepositoryException e) { 092 throw new SQLException(e.getLocalizedMessage()); 093 } 094 } 095 096 @Override 097 public boolean isReadOnly() throws SQLException { 098 notClosed(); 099 return true; // always read-only 100 } 101 102 @Override 103 public void setReadOnly( boolean readOnly ) throws SQLException { 104 notClosed(); 105 } 106 107 @Override 108 public boolean isValid( int timeout ) throws SQLException { 109 if (closed) return false; 110 if (timeout < 0) throw new SQLException(JdbcLocalI18n.timeoutMayNotBeNegative.text()); 111 try { 112 return this.getRepositoryDelegate().isValid(timeout); 113 } catch (RepositoryException e) { 114 throw new SQLException(e.getLocalizedMessage()); 115 } 116 } 117 118 @Override 119 public void close() { 120 if (!closed) { 121 try { 122 this.getRepositoryDelegate().close(); 123 } finally { 124 metadata = null; 125 closed = true; 126 } 127 } 128 } 129 130 @Override 131 public boolean isClosed() { 132 return closed; 133 } 134 135 protected final void notClosed() throws SQLException { 136 if (isClosed()) throw new SQLException(JdbcLocalI18n.connectionIsClosed.text()); 137 } 138 139 @Override 140 public void commit() throws SQLException { 141 notClosed(); 142 try { 143 this.getRepositoryDelegate().commit(); 144 } catch (RepositoryException e) { 145 throw new SQLException(e.getLocalizedMessage()); 146 } 147 } 148 149 @Override 150 public void rollback() throws SQLException { 151 notClosed(); 152 try { 153 this.getRepositoryDelegate().rollback(); 154 } catch (RepositoryException e) { 155 throw new SQLException(e.getLocalizedMessage()); 156 } 157 } 158 159 @Override 160 public void rollback( Savepoint savepoint ) throws SQLException { 161 throw new SQLFeatureNotSupportedException(); 162 } 163 164 @Override 165 public void clearWarnings() throws SQLException { 166 notClosed(); 167 warning = null; 168 } 169 170 @Override 171 public SQLWarning getWarnings() throws SQLException { 172 notClosed(); 173 return warning; 174 } 175 176 @Override 177 public boolean getAutoCommit() throws SQLException { 178 notClosed(); 179 return autoCommit; 180 } 181 182 @Override 183 public void setAutoCommit( boolean autoCommit ) throws SQLException { 184 notClosed(); 185 this.autoCommit = autoCommit; 186 } 187 188 @Override 189 public int getTransactionIsolation() throws SQLException { 190 notClosed(); 191 return Connection.TRANSACTION_READ_COMMITTED; 192 } 193 194 @Override 195 public void setTransactionIsolation( int level ) throws SQLException { 196 notClosed(); 197 // silently ignore 198 } 199 200 @Override 201 public Savepoint setSavepoint() throws SQLException { 202 throw new SQLFeatureNotSupportedException(); 203 } 204 205 @Override 206 public Savepoint setSavepoint( String name ) throws SQLException { 207 throw new SQLFeatureNotSupportedException(); 208 } 209 210 @Override 211 public void releaseSavepoint( Savepoint savepoint ) throws SQLException { 212 throw new SQLFeatureNotSupportedException(); 213 } 214 215 @Override 216 public String getCatalog() { 217 return this.info().getRepositoryName(); 218 } 219 220 @Override 221 public void setCatalog( String catalog ) { 222 // silently ignore 223 } 224 225 @Override 226 public Properties getClientInfo() /*throws SQLException*/{ 227 return clientInfo; 228 } 229 230 @Override 231 public String getClientInfo( String name ) /*throws SQLException*/{ 232 return clientInfo.getProperty(name); 233 } 234 235 @Override 236 public void setClientInfo( Properties properties ) throws SQLClientInfoException { 237 Map<String, ClientInfoStatus> status = new HashMap<String, ClientInfoStatus>(); 238 Properties validProperties = new Properties(); 239 for (String name : properties.stringPropertyNames()) { 240 // Don't override the built-in properties ... 241 if (name == null || LocalJcrDriver.ALL_PROPERTY_NAMES.contains(name)) { 242 status.put(name, ClientInfoStatus.REASON_VALUE_INVALID); 243 } else { 244 String value = properties.getProperty(name); 245 validProperties.put(name, value); 246 } 247 } 248 if (validProperties.isEmpty()) { 249 if (!status.isEmpty()) { 250 String reason = JdbcLocalI18n.invalidClientInfo.text(); 251 throw new SQLClientInfoException(reason, status); 252 } 253 } else { 254 clientInfo.putAll(validProperties); 255 } 256 } 257 258 @Override 259 public void setClientInfo( String name, 260 String value ) throws SQLClientInfoException { 261 Properties properties = new Properties(); 262 properties.put(name, value); 263 setClientInfo(properties); 264 } 265 266 @Override 267 public int getHoldability() throws SQLException { 268 throw new SQLFeatureNotSupportedException(); 269 } 270 271 @Override 272 public void setHoldability( int holdability ) throws SQLException { 273 throw new SQLFeatureNotSupportedException(); 274 } 275 276 @Override 277 public DatabaseMetaData getMetaData() throws SQLException { 278 notClosed(); 279 if (metadata == null) { 280 String descriptor = this.getRepositoryDelegate().getDescriptor(Repository.REP_NAME_DESC); 281 if (descriptor != null && descriptor.toLowerCase().contains("modeshape")) { 282 return new ModeShapeMetaData(this); 283 } 284 return new JcrMetaData(this); 285 } 286 return metadata; 287 } 288 289 @Override 290 public Map<String, Class<?>> getTypeMap() { 291 return new HashMap<String, Class<?>>(1); 292 } 293 294 @Override 295 public void setTypeMap( Map<String, Class<?>> map ) throws SQLException { 296 throw new SQLFeatureNotSupportedException(); 297 } 298 299 /** 300 * {@inheritDoc} 301 * <p> 302 * This method pre-processes the supplied SQL-compatible query and returns the corresponding JCR-SQL2. 303 * </p> 304 * 305 * @see java.sql.Connection#nativeSQL(java.lang.String) 306 */ 307 @Override 308 public String nativeSQL( String sql ) { 309 return sql; 310 } 311 312 @SuppressWarnings( "unused" ) 313 @Override 314 public Statement createStatement() throws SQLException { 315 return new JcrStatement(this); 316 } 317 318 @Override 319 public Statement createStatement( int resultSetType, 320 int resultSetConcurrency ) throws SQLException { 321 throw new SQLFeatureNotSupportedException(); 322 } 323 324 @Override 325 public Statement createStatement( int resultSetType, 326 int resultSetConcurrency, 327 int resultSetHoldability ) throws SQLException { 328 throw new SQLFeatureNotSupportedException(); 329 } 330 331 @Override 332 public PreparedStatement prepareStatement( String sql ) throws SQLException { 333 throw new SQLFeatureNotSupportedException(); 334 } 335 336 @Override 337 public PreparedStatement prepareStatement( String sql, 338 int autoGeneratedKeys ) throws SQLException { 339 throw new SQLFeatureNotSupportedException(); 340 } 341 342 @Override 343 public PreparedStatement prepareStatement( String sql, 344 int[] columnIndexes ) throws SQLException { 345 throw new SQLFeatureNotSupportedException(); 346 } 347 348 @Override 349 public PreparedStatement prepareStatement( String sql, 350 String[] columnNames ) throws SQLException { 351 throw new SQLFeatureNotSupportedException(); 352 } 353 354 @Override 355 public PreparedStatement prepareStatement( String sql, 356 int resultSetType, 357 int resultSetConcurrency ) throws SQLException { 358 throw new SQLFeatureNotSupportedException(); 359 } 360 361 @Override 362 public PreparedStatement prepareStatement( String sql, 363 int resultSetType, 364 int resultSetConcurrency, 365 int resultSetHoldability ) throws SQLException { 366 throw new SQLFeatureNotSupportedException(); 367 } 368 369 @Override 370 public CallableStatement prepareCall( String sql ) throws SQLException { 371 throw new SQLFeatureNotSupportedException(); 372 } 373 374 @Override 375 public CallableStatement prepareCall( String sql, 376 int resultSetType, 377 int resultSetConcurrency ) throws SQLException { 378 throw new SQLFeatureNotSupportedException(); 379 } 380 381 @Override 382 public CallableStatement prepareCall( String sql, 383 int resultSetType, 384 int resultSetConcurrency, 385 int resultSetHoldability ) throws SQLException { 386 throw new SQLFeatureNotSupportedException(); 387 } 388 389 @Override 390 public Array createArrayOf( String typeName, 391 Object[] elements ) throws SQLException { 392 throw new SQLFeatureNotSupportedException(); 393 } 394 395 @Override 396 public Blob createBlob() throws SQLException { 397 notClosed(); 398 throw new SQLFeatureNotSupportedException(); 399 } 400 401 @Override 402 public Clob createClob() throws SQLException { 403 notClosed(); 404 throw new SQLFeatureNotSupportedException(); 405 } 406 407 @Override 408 public NClob createNClob() throws SQLException { 409 notClosed(); 410 throw new SQLFeatureNotSupportedException(); 411 } 412 413 @Override 414 public SQLXML createSQLXML() throws SQLException { 415 notClosed(); 416 throw new SQLFeatureNotSupportedException(); 417 } 418 419 @Override 420 public Struct createStruct( String typeName, 421 Object[] attributes ) throws SQLException { 422 notClosed(); 423 throw new SQLFeatureNotSupportedException(); 424 } 425 426 @Override 427 public boolean isWrapperFor( Class<?> iface ) /*throws SQLException*/{ 428 return iface.isInstance(this) || this.getRepositoryDelegate().isWrapperFor(iface); 429 } 430 431 @Override 432 public <T> T unwrap( Class<T> iface ) throws SQLException { 433 if (isWrapperFor(iface)) { 434 return iface.cast(this); 435 } 436 return getRepositoryDelegate().unwrap(iface); 437 } 438 439 @Override 440 public void setSchema( String schema ) { 441 } 442 443 @Override 444 public String getSchema() { 445 return null; 446 } 447 448 @Override 449 public void abort( Executor executor ) { 450 } 451 452 @Override 453 public void setNetworkTimeout( Executor executor, 454 int milliseconds ) throws SQLException { 455 throw new SQLFeatureNotSupportedException(); 456 } 457 458 @Override 459 public int getNetworkTimeout() throws SQLException { 460 throw new SQLFeatureNotSupportedException(); 461 } 462}