%line | %branch | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
org.apache.jetspeed.components.rdbms.ojb.ConnectionRepositoryEntry$MinimalDataSource |
|
|
1 | /* |
|
2 | * Licensed to the Apache Software Foundation (ASF) under one or more |
|
3 | * contributor license agreements. See the NOTICE file distributed with |
|
4 | * this work for additional information regarding copyright ownership. |
|
5 | * The ASF licenses this file to You under the Apache License, Version 2.0 |
|
6 | * (the "License"); you may not use this file except in compliance with |
|
7 | * the License. You may obtain a copy of the License at |
|
8 | * |
|
9 | * http://www.apache.org/licenses/LICENSE-2.0 |
|
10 | * |
|
11 | * Unless required by applicable law or agreed to in writing, software |
|
12 | * distributed under the License is distributed on an "AS IS" BASIS, |
|
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
14 | * See the License for the specific language governing permissions and |
|
15 | * limitations under the License. |
|
16 | */ |
|
17 | package org.apache.jetspeed.components.rdbms.ojb; |
|
18 | ||
19 | import java.io.PrintWriter; |
|
20 | import java.sql.Connection; |
|
21 | import java.sql.DatabaseMetaData; |
|
22 | import java.sql.DriverManager; |
|
23 | import java.sql.SQLException; |
|
24 | import java.util.Map; |
|
25 | ||
26 | import javax.naming.Context; |
|
27 | import javax.naming.InitialContext; |
|
28 | import javax.sql.DataSource; |
|
29 | ||
30 | import org.apache.commons.dbcp.BasicDataSource; |
|
31 | import org.apache.commons.logging.Log; |
|
32 | import org.apache.commons.logging.LogFactory; |
|
33 | import org.apache.ojb.broker.PBKey; |
|
34 | import org.apache.ojb.broker.accesslayer.ConnectionFactoryDBCPImpl; |
|
35 | import org.apache.ojb.broker.accesslayer.ConnectionFactoryManagedImpl; |
|
36 | import org.apache.ojb.broker.accesslayer.LookupException; |
|
37 | import org.apache.ojb.broker.metadata.ConnectionPoolDescriptor; |
|
38 | import org.apache.ojb.broker.metadata.ConnectionRepository; |
|
39 | import org.apache.ojb.broker.metadata.JdbcConnectionDescriptor; |
|
40 | import org.apache.ojb.broker.metadata.JdbcMetadataUtils; |
|
41 | import org.apache.ojb.broker.metadata.MetadataManager; |
|
42 | import org.apache.ojb.broker.util.ClassHelper; |
|
43 | import org.springframework.beans.factory.BeanNameAware; |
|
44 | import org.springframework.beans.factory.InitializingBean; |
|
45 | ||
46 | /** |
|
47 | * A JavaBean that configures an entry in OJB's ConnectionRepository |
|
48 | * according to its properties. If a JCD alias is not specified, it defaults |
|
49 | * to the bean's name in the Spring configuration. If the JDBC connection |
|
50 | * descriptor already exists (e.g. because it has been defined in OJB's |
|
51 | * configuration) the properties are merged into the existing descriptor |
|
52 | * (see note about "platform" below), else the JDBC connection descriptor |
|
53 | * is created.<P> |
|
54 | * |
|
55 | * If a JNDI name is set, the bean automatically configures a JDBC connection |
|
56 | * descriptor with a connection factory of type |
|
57 | * <code>ConnectionFactoryManagedImpl</code>, else it uses |
|
58 | * <code>ConectionFactoryDBCPImpl</code>. This may be overridden my setting |
|
59 | * the connection factory property explicitly.<P> |
|
60 | * |
|
61 | * Properties "driverClassName", "url", "username" and "password" are used |
|
62 | * only if no JNDI name is set, i.e. if the connection factory uses the |
|
63 | * driver to create data sources.<P> |
|
64 | * |
|
65 | * The bean derives the RDBMS platform setting from the configured |
|
66 | * data source or database driver using OJB's <code>JdbcMetadataUtils</code> |
|
67 | * class. At least until OJB 1.0.3, however, this class does not properly |
|
68 | * distinguish the platforms "Oracle" and "Oracle9i"; it always assigns |
|
69 | * "Oracle". In case of "Oracle", this bean therefore opens a connection, |
|
70 | * obtains the version information from the database server and adjusts the |
|
71 | * platform accordingly. This behaviour may be overridden by setting the |
|
72 | * <code>platform</code> property of the bean explicitly. Note that the |
|
73 | * attribute "platform" of an already existing JCD is ignored. An already |
|
74 | * existing JCD stems most likely from a configuration file "repository.xml". |
|
75 | * As the DTD for "repository.xml" ("repository.dtd") defines a default |
|
76 | * value for attribute "platform" ("Hsqldb"), it is in general impossible |
|
77 | * to find out whether the platform attribute of an existing JCD has been set |
|
78 | * explicitly or has simply assumed its default value. |
|
79 | * |
|
80 | * @author Michael Lipp |
|
81 | * @version $Id$ |
|
82 | */ |
|
83 | public class ConnectionRepositoryEntry |
|
84 | extends BasicDataSource |
|
85 | implements BeanNameAware, InitializingBean |
|
86 | { |
|
87 | private static final Log log = LogFactory.getLog(ConnectionRepositoryEntry.class); |
|
88 | ||
89 | // general properties |
|
90 | private String jcdAlias = null; |
|
91 | private String platform = null; |
|
92 | private String connectionFactoryClass = null; |
|
93 | // properties for obtaining data source from JNDI |
|
94 | private String jndiName = null; |
|
95 | // properties for creating independant data source |
|
96 | private String driverClassName = null; |
|
97 | private String url = null; |
|
98 | private String username = null; |
|
99 | private String password = null; |
|
100 | private boolean jetspeedEngineScoped = true; |
|
101 | ||
102 | private DataSource externalDs; |
|
103 | ||
104 | public ConnectionRepositoryEntry() |
|
105 | { |
|
106 | super(); |
|
107 | } |
|
108 | ||
109 | /** |
|
110 | * @see org.springframework.beans.factory.BeanNameAware#setBeanName(java.lang.String) |
|
111 | */ |
|
112 | public void setBeanName(String beanName) |
|
113 | { |
|
114 | // Use the bean's name as fallback if a JCD alias is not set |
|
115 | // explicitly |
|
116 | if (jcdAlias == null) |
|
117 | { |
|
118 | jcdAlias = beanName; |
|
119 | } |
|
120 | } |
|
121 | ||
122 | /** |
|
123 | * @return Returns the jcdAlias. |
|
124 | */ |
|
125 | public String getJcdAlias() |
|
126 | { |
|
127 | return jcdAlias; |
|
128 | } |
|
129 | ||
130 | /** |
|
131 | * @param jcdAlias The jcdAlias to set. |
|
132 | */ |
|
133 | public void setJcdAlias(String jcdAlias) |
|
134 | { |
|
135 | this.jcdAlias = jcdAlias; |
|
136 | } |
|
137 | ||
138 | /** |
|
139 | * @return Returns the jndiName. |
|
140 | */ |
|
141 | public String getJndiName() |
|
142 | { |
|
143 | return jndiName; |
|
144 | } |
|
145 | ||
146 | /** |
|
147 | * @param jndiName The jndiName to set. |
|
148 | */ |
|
149 | public void setJndiName(String jndiName) |
|
150 | { |
|
151 | this.jndiName = jndiName; |
|
152 | } |
|
153 | ||
154 | /** |
|
155 | * @return Returns the driverClassName. |
|
156 | */ |
|
157 | public String getDriverClassName() |
|
158 | { |
|
159 | return driverClassName; |
|
160 | } |
|
161 | ||
162 | /** |
|
163 | * @param driverClassName The driverClassName to set. |
|
164 | */ |
|
165 | public void setDriverClassName(String driverClassName) |
|
166 | { |
|
167 | super.setDriverClassName(driverClassName); |
|
168 | this.driverClassName = driverClassName; |
|
169 | } |
|
170 | ||
171 | /** |
|
172 | * @return Returns the password. |
|
173 | */ |
|
174 | public String getPassword() |
|
175 | { |
|
176 | return password; |
|
177 | } |
|
178 | ||
179 | /** |
|
180 | * @param password The password to set. |
|
181 | */ |
|
182 | public void setPassword(String password) |
|
183 | { |
|
184 | super.setPassword(password); |
|
185 | this.password = password; |
|
186 | } |
|
187 | ||
188 | /** |
|
189 | * @return Returns the url. |
|
190 | */ |
|
191 | public String getUrl() |
|
192 | { |
|
193 | return url; |
|
194 | } |
|
195 | ||
196 | /** |
|
197 | * @param url The url to set. |
|
198 | */ |
|
199 | public void setUrl(String url) |
|
200 | { |
|
201 | super.setUrl(url); |
|
202 | this.url = url; |
|
203 | } |
|
204 | ||
205 | /** |
|
206 | * @return Returns the username. |
|
207 | */ |
|
208 | public String getUsername() |
|
209 | { |
|
210 | return username; |
|
211 | } |
|
212 | ||
213 | /** |
|
214 | * @param username The username to set. |
|
215 | */ |
|
216 | public void setUsername(String username) |
|
217 | { |
|
218 | super.setUsername(username); |
|
219 | this.username = username; |
|
220 | } |
|
221 | ||
222 | /** |
|
223 | * @return Returns the platform. |
|
224 | */ |
|
225 | public String getPlatform() |
|
226 | { |
|
227 | return platform; |
|
228 | } |
|
229 | ||
230 | /** |
|
231 | * Set the platform attribute of the JCD. Setting this property overrides |
|
232 | * the value derived from the data source or database driver. |
|
233 | * @param platform The platform to set. |
|
234 | */ |
|
235 | public void setPlatform(String platform) |
|
236 | { |
|
237 | this.platform = platform; |
|
238 | } |
|
239 | ||
240 | /** |
|
241 | * @see setJetspeedEngineScoped |
|
242 | * @return Returns if Jetspeed engine's ENC is used for JNDI lookups. |
|
243 | */ |
|
244 | public boolean isJetspeedEngineScoped() |
|
245 | { |
|
246 | return jetspeedEngineScoped; |
|
247 | } |
|
248 | ||
249 | /** |
|
250 | * Sets the attribute "<code>org.apache.jetspeed.engineScoped</code>" |
|
251 | * of the JDBC connection descriptor to "<code>true</code>" or |
|
252 | * "<code>false</code>". If set, JNDI lookups of the connection will |
|
253 | * be done using the environment naming context (ENC) of the Jetspeed |
|
254 | * engine. |
|
255 | * @param jetspeedEngineScoped whether to use Jetspeed engine's ENC. |
|
256 | */ |
|
257 | public void setJetspeedEngineScoped(boolean jetspeedEngineScoped) |
|
258 | { |
|
259 | this.jetspeedEngineScoped = jetspeedEngineScoped; |
|
260 | } |
|
261 | ||
262 | public void afterPropertiesSet () throws Exception |
|
263 | { |
|
264 | // Try to find JCD |
|
265 | ConnectionRepository cr = MetadataManager.getInstance().connectionRepository(); |
|
266 | JdbcConnectionDescriptor jcd = cr.getDescriptor(new PBKey(jcdAlias)); |
|
267 | if (jcd == null) |
|
268 | { |
|
269 | jcd = new JdbcConnectionDescriptor(); |
|
270 | jcd.setJcdAlias(jcdAlias); |
|
271 | cr.addDescriptor(jcd); |
|
272 | } |
|
273 | if (platform != null && platform.length() == 0) |
|
274 | { |
|
275 | platform = null; |
|
276 | } |
|
277 | DataSource ds = null; |
|
278 | JdbcMetadataUtils jdbcMetadataUtils = new JdbcMetadataUtils (); |
|
279 | if (jndiName != null) |
|
280 | { |
|
281 | // using "preconfigured" data source |
|
282 | if (connectionFactoryClass == null) |
|
283 | { |
|
284 | connectionFactoryClass = ConnectionFactoryManagedImpl.class.getName (); |
|
285 | } |
|
286 | Context initialContext = new InitialContext(); |
|
287 | ds = (DataSource) initialContext.lookup(jndiName); |
|
288 | externalDs = ds; |
|
289 | jcd.setDatasourceName(jndiName); |
|
290 | } |
|
291 | else |
|
292 | { |
|
293 | // have to get data source ourselves |
|
294 | if (connectionFactoryClass == null) |
|
295 | { |
|
296 | connectionFactoryClass = ConnectionFactoryDBCPImpl.class.getName (); |
|
297 | } |
|
298 | jcd.setDriver(driverClassName); |
|
299 | Map conData = jdbcMetadataUtils.parseConnectionUrl(url); |
|
300 | jcd.setDbms(platform); |
|
301 | jcd.setProtocol((String)conData.get(JdbcMetadataUtils.PROPERTY_PROTOCOL)); |
|
302 | jcd.setSubProtocol((String)conData.get(JdbcMetadataUtils.PROPERTY_SUBPROTOCOL)); |
|
303 | jcd.setDbAlias((String)conData.get(JdbcMetadataUtils.PROPERTY_DBALIAS)); |
|
304 | jcd.setUserName(username); |
|
305 | jcd.setPassWord(password); |
|
306 | // Wrapping the connection factory in a DataSource introduces a bit |
|
307 | // of redundancy (url is parsed again and platform determined again). |
|
308 | // But although JdbcMetadataUtils exposes the methods used in |
|
309 | // fillJCDFromDataSource as public (and these do not require a DataSource) |
|
310 | // the method itself does more than is made available by the exposed methods. |
|
311 | // ds = new MinimalDataSource (jcd); |
|
312 | ds = this; |
|
313 | } |
|
314 | ConnectionPoolDescriptor cpd = jcd.getConnectionPoolDescriptor(); |
|
315 | if (cpd == null) |
|
316 | { |
|
317 | cpd = new ConnectionPoolDescriptor(); |
|
318 | jcd.setConnectionPoolDescriptor(cpd); |
|
319 | } |
|
320 | Class conFacCls = ClassHelper.getClass(connectionFactoryClass); |
|
321 | cpd.setConnectionFactory(conFacCls); |
|
322 | ||
323 | jdbcMetadataUtils.fillJCDFromDataSource(jcd, ds, null, class="keyword">null); |
|
324 | ||
325 | if (platform == null && JdbcMetadataUtils.PLATFORM_ORACLE.equals(jcd.getDbms())) { |
|
326 | // Postprocess to find Oracle version. |
|
327 | updateOraclePlatform (jcd, ds); |
|
328 | } |
|
329 | // if platform has explicitly been set, the value takes precedence |
|
330 | if (platform != null) { |
|
331 | if (!platform.equals(jcd.getDbms())) { |
|
332 | log.warn ("Automatically derived RDBMS platform \"" + jcd.getDbms() |
|
333 | + "\" differs from explicitly set platform \"" + platform + "\""); |
|
334 | } |
|
335 | jcd.setDbms(platform); |
|
336 | } else { |
|
337 | platform = jcd.getDbms(); |
|
338 | } |
|
339 | ||
340 | // special attributes |
|
341 | jcd.addAttribute("org.apache.jetspeed.engineScoped", |
|
342 | Boolean.toString(jetspeedEngineScoped)); |
|
343 | } |
|
344 | ||
345 | /** |
|
346 | * @param jcd |
|
347 | * @throws LookupException |
|
348 | * @throws IllegalAccessException |
|
349 | * @throws InstantiationException |
|
350 | * throws SQLException |
|
351 | */ |
|
352 | private void updateOraclePlatform(JdbcConnectionDescriptor jcd, DataSource ds) |
|
353 | throws LookupException, IllegalAccessException, InstantiationException, SQLException |
|
354 | { |
|
355 | Connection con = null; |
|
356 | try |
|
357 | { |
|
358 | con = ds.getConnection(); |
|
359 | DatabaseMetaData metaData = con.getMetaData(); |
|
360 | int rdbmsVersion = 0; |
|
361 | try |
|
362 | { |
|
363 | // getDatabaseMajorVersion exists since 1.4, so it may |
|
364 | // not be defined for the driver used. |
|
365 | rdbmsVersion = metaData.getDatabaseMajorVersion(); |
|
366 | } catch (Throwable t) { |
|
367 | String dbVersion = metaData.getDatabaseProductVersion(); |
|
368 | String relKey = "Release"; |
|
369 | String major = dbVersion; |
|
370 | int startPos = dbVersion.indexOf(relKey); |
|
371 | if (startPos < 0) |
|
372 | { |
|
373 | log.warn ("Cannot determine Oracle version, no \"Release\" in procuct version: \"" + dbVersion + "\""); |
|
374 | return; |
|
375 | } |
|
376 | startPos += relKey.length(); |
|
377 | int dotPos = dbVersion.indexOf('.', startPos); |
|
378 | if (dotPos > 0) { |
|
379 | major = dbVersion.substring(startPos, dotPos).trim(); |
|
380 | } |
|
381 | try |
|
382 | { |
|
383 | rdbmsVersion = Integer.parseInt(major); |
|
384 | } |
|
385 | catch (NumberFormatException e) |
|
386 | { |
|
387 | log.warn ("Cannot determine Oracle version, product version \"" + dbVersion + "\" not layed out as \"... Release N.M.....\""); |
|
388 | return; |
|
389 | } |
|
390 | if (log.isDebugEnabled()) |
|
391 | { |
|
392 | log.debug ("Extracted Oracle major version " + rdbmsVersion + " from product version \"" + dbVersion + "\""); |
|
393 | } |
|
394 | } |
|
395 | if (rdbmsVersion >= 9) { |
|
396 | jcd.setDbms(JdbcMetadataUtils.PLATFORM_ORACLE9I); |
|
397 | } |
|
398 | } |
|
399 | finally |
|
400 | { |
|
401 | if (con != null) { |
|
402 | con.close (); |
|
403 | } |
|
404 | } |
|
405 | } |
|
406 | ||
407 | /** |
|
408 | * a minimal DataSource implementation that satisfies the requirements |
|
409 | * of JdbcMetadataUtil. |
|
410 | */ |
|
411 | private class MinimalDataSource implements DataSource |
|
412 | { |
|
413 | 0 | private JdbcConnectionDescriptor jcd = null; |
414 | ||
415 | /** |
|
416 | * Create a new instance using the given JCD. |
|
417 | */ |
|
418 | public MinimalDataSource (JdbcConnectionDescriptor jcd) |
|
419 | 0 | { |
420 | 0 | this.jcd = jcd; |
421 | 0 | } |
422 | ||
423 | /* (non-Javadoc) |
|
424 | * @see javax.sql.DataSource#getConnection() |
|
425 | */ |
|
426 | public Connection getConnection() throws SQLException { |
|
427 | // Use JDBC DriverManager as we may not rely on JCD to be sufficiently |
|
428 | // initialized to use any of the ConnectionFactories. |
|
429 | try { |
|
430 | // loads the driver - NB call to newInstance() added to force initialisation |
|
431 | 0 | ClassHelper.getClass(jcd.getDriver(), true); |
432 | 0 | String url = jcd.getProtocol() + ":" + jcd.getSubProtocol() + ":" + jcd.getDbAlias(); |
433 | 0 | if (jcd.getUserName() == null) |
434 | { |
|
435 | 0 | return DriverManager.getConnection(url); |
436 | } |
|
437 | else |
|
438 | { |
|
439 | 0 | return DriverManager.getConnection(url, jcd.getUserName(), jcd.getPassWord()); |
440 | } |
|
441 | } |
|
442 | 0 | catch (ClassNotFoundException e) |
443 | { |
|
444 | 0 | throw (IllegalStateException) |
445 | (new IllegalStateException (e.getMessage ())).initCause (e); |
|
446 | } |
|
447 | } |
|
448 | ||
449 | /** |
|
450 | * @see javax.sql.DataSource#getConnection(java.lang.String, java.lang.String) |
|
451 | */ |
|
452 | public Connection getConnection(String username, String password) |
|
453 | throws SQLException { |
|
454 | 0 | return getConnection (); |
455 | } |
|
456 | ||
457 | /** |
|
458 | * @see javax.sql.DataSource#getLoginTimeout() |
|
459 | */ |
|
460 | public int getLoginTimeout() throws SQLException |
|
461 | { |
|
462 | 0 | return 0; |
463 | } |
|
464 | ||
465 | /** |
|
466 | * @see javax.sql.DataSource#getLogWriter() |
|
467 | */ |
|
468 | public PrintWriter getLogWriter() throws SQLException { |
|
469 | 0 | return null; |
470 | } |
|
471 | ||
472 | /** |
|
473 | * @see javax.sql.DataSource#setLoginTimeout(int) |
|
474 | */ |
|
475 | public void setLoginTimeout(int seconds) throws SQLException { |
|
476 | 0 | } |
477 | ||
478 | /** |
|
479 | * @see javax.sql.DataSource#setLogWriter(java.io.PrintWriter) |
|
480 | */ |
|
481 | public void setLogWriter(PrintWriter out) throws SQLException { |
|
482 | 0 | } |
483 | } |
|
484 | ||
485 | public Connection getConnection() throws SQLException { |
|
486 | if(externalDs != null) |
|
487 | { |
|
488 | return externalDs.getConnection(); |
|
489 | } |
|
490 | else |
|
491 | { |
|
492 | return super.getConnection(); |
|
493 | } |
|
494 | } |
|
495 | ||
496 | public Connection getConnection(String username, String password) |
|
497 | throws SQLException { |
|
498 | ||
499 | if(externalDs != null) |
|
500 | { |
|
501 | return externalDs.getConnection(username, password); |
|
502 | } |
|
503 | else |
|
504 | { |
|
505 | return super.getConnection(username, password); |
|
506 | } |
|
507 | } |
|
508 | ||
509 | } |
This report is generated by jcoverage, Maven and Maven JCoverage Plugin. |