%line | %branch | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
org.apache.jetspeed.components.rdbms.ojb.ConnectionRepositoryEntry |
|
|
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 | 0 | private static final Log log = LogFactory.getLog(ConnectionRepositoryEntry.class); |
88 | ||
89 | // general properties |
|
90 | 0 | private String jcdAlias = null; |
91 | 0 | private String platform = null; |
92 | 0 | private String connectionFactoryClass = null; |
93 | // properties for obtaining data source from JNDI |
|
94 | 0 | private String jndiName = null; |
95 | // properties for creating independant data source |
|
96 | 0 | private String driverClassName = null; |
97 | 0 | private String url = null; |
98 | 0 | private String username = null; |
99 | 0 | private String password = null; |
100 | 0 | private boolean jetspeedEngineScoped = true; |
101 | ||
102 | public ConnectionRepositoryEntry() |
|
103 | { |
|
104 | 0 | super(); |
105 | 0 | } |
106 | ||
107 | /** |
|
108 | * @see org.springframework.beans.factory.BeanNameAware#setBeanName(java.lang.String) |
|
109 | */ |
|
110 | public void setBeanName(String beanName) |
|
111 | { |
|
112 | // Use the bean's name as fallback if a JCD alias is not set |
|
113 | // explicitly |
|
114 | 0 | if (jcdAlias == null) |
115 | { |
|
116 | 0 | jcdAlias = beanName; |
117 | } |
|
118 | 0 | } |
119 | ||
120 | /** |
|
121 | * @return Returns the jcdAlias. |
|
122 | */ |
|
123 | public String getJcdAlias() |
|
124 | { |
|
125 | 0 | return jcdAlias; |
126 | } |
|
127 | ||
128 | /** |
|
129 | * @param jcdAlias The jcdAlias to set. |
|
130 | */ |
|
131 | public void setJcdAlias(String jcdAlias) |
|
132 | { |
|
133 | 0 | this.jcdAlias = jcdAlias; |
134 | 0 | } |
135 | ||
136 | /** |
|
137 | * @return Returns the jndiName. |
|
138 | */ |
|
139 | public String getJndiName() |
|
140 | { |
|
141 | 0 | return jndiName; |
142 | } |
|
143 | ||
144 | /** |
|
145 | * @param jndiName The jndiName to set. |
|
146 | */ |
|
147 | public void setJndiName(String jndiName) |
|
148 | { |
|
149 | 0 | this.jndiName = jndiName; |
150 | 0 | } |
151 | ||
152 | /** |
|
153 | * @return Returns the driverClassName. |
|
154 | */ |
|
155 | public String getDriverClassName() |
|
156 | { |
|
157 | 0 | return driverClassName; |
158 | } |
|
159 | ||
160 | /** |
|
161 | * @param driverClassName The driverClassName to set. |
|
162 | */ |
|
163 | public void setDriverClassName(String driverClassName) |
|
164 | { |
|
165 | 0 | super.setDriverClassName(driverClassName); |
166 | 0 | this.driverClassName = driverClassName; |
167 | 0 | } |
168 | ||
169 | /** |
|
170 | * @return Returns the password. |
|
171 | */ |
|
172 | public String getPassword() |
|
173 | { |
|
174 | 0 | return password; |
175 | } |
|
176 | ||
177 | /** |
|
178 | * @param password The password to set. |
|
179 | */ |
|
180 | public void setPassword(String password) |
|
181 | { |
|
182 | 0 | super.setPassword(password); |
183 | 0 | this.password = password; |
184 | 0 | } |
185 | ||
186 | /** |
|
187 | * @return Returns the url. |
|
188 | */ |
|
189 | public String getUrl() |
|
190 | { |
|
191 | 0 | return url; |
192 | } |
|
193 | ||
194 | /** |
|
195 | * @param url The url to set. |
|
196 | */ |
|
197 | public void setUrl(String url) |
|
198 | { |
|
199 | 0 | super.setUrl(url); |
200 | 0 | this.url = url; |
201 | 0 | } |
202 | ||
203 | /** |
|
204 | * @return Returns the username. |
|
205 | */ |
|
206 | public String getUsername() |
|
207 | { |
|
208 | 0 | return username; |
209 | } |
|
210 | ||
211 | /** |
|
212 | * @param username The username to set. |
|
213 | */ |
|
214 | public void setUsername(String username) |
|
215 | { |
|
216 | 0 | super.setUsername(username); |
217 | 0 | this.username = username; |
218 | 0 | } |
219 | ||
220 | /** |
|
221 | * @return Returns the platform. |
|
222 | */ |
|
223 | public String getPlatform() |
|
224 | { |
|
225 | 0 | return platform; |
226 | } |
|
227 | ||
228 | /** |
|
229 | * Set the platform attribute of the JCD. Setting this property overrides |
|
230 | * the value derived from the data source or database driver. |
|
231 | * @param platform The platform to set. |
|
232 | */ |
|
233 | public void setPlatform(String platform) |
|
234 | { |
|
235 | 0 | this.platform = platform; |
236 | 0 | } |
237 | ||
238 | /** |
|
239 | * @see setJetspeedEngineScoped |
|
240 | * @return Returns if Jetspeed engine's ENC is used for JNDI lookups. |
|
241 | */ |
|
242 | public boolean isJetspeedEngineScoped() |
|
243 | { |
|
244 | 0 | return jetspeedEngineScoped; |
245 | } |
|
246 | ||
247 | /** |
|
248 | * Sets the attribute "<code>org.apache.jetspeed.engineScoped</code>" |
|
249 | * of the JDBC connection descriptor to "<code>true</code>" or |
|
250 | * "<code>false</code>". If set, JNDI lookups of the connection will |
|
251 | * be done using the environment naming context (ENC) of the Jetspeed |
|
252 | * engine. |
|
253 | * @param jetspeedEngineScoped whether to use Jetspeed engine's ENC. |
|
254 | */ |
|
255 | public void setJetspeedEngineScoped(boolean jetspeedEngineScoped) |
|
256 | { |
|
257 | 0 | this.jetspeedEngineScoped = jetspeedEngineScoped; |
258 | 0 | } |
259 | ||
260 | public void afterPropertiesSet () throws Exception |
|
261 | { |
|
262 | // Try to find JCD |
|
263 | 0 | ConnectionRepository cr = MetadataManager.getInstance().connectionRepository(); |
264 | 0 | JdbcConnectionDescriptor jcd = cr.getDescriptor(new PBKey(jcdAlias)); |
265 | 0 | if (jcd == null) |
266 | { |
|
267 | 0 | jcd = new JdbcConnectionDescriptor(); |
268 | 0 | jcd.setJcdAlias(jcdAlias); |
269 | 0 | cr.addDescriptor(jcd); |
270 | } |
|
271 | 0 | if (platform != null && platform.length() == 0) |
272 | { |
|
273 | 0 | platform = null; |
274 | } |
|
275 | 0 | DataSource ds = null; |
276 | 0 | JdbcMetadataUtils jdbcMetadataUtils = new JdbcMetadataUtils (); |
277 | 0 | if (jndiName != null) |
278 | { |
|
279 | // using "preconfigured" data source |
|
280 | 0 | if (connectionFactoryClass == null) |
281 | { |
|
282 | 0 | connectionFactoryClass = ConnectionFactoryManagedImpl.class.getName (); |
283 | } |
|
284 | 0 | Context initialContext = new InitialContext(); |
285 | 0 | ds = (DataSource) initialContext.lookup(jndiName); |
286 | 0 | jcd.setDatasourceName(jndiName); |
287 | 0 | } |
288 | else |
|
289 | { |
|
290 | // have to get data source ourselves |
|
291 | 0 | if (connectionFactoryClass == null) |
292 | { |
|
293 | 0 | connectionFactoryClass = ConnectionFactoryDBCPImpl.class.getName (); |
294 | } |
|
295 | 0 | jcd.setDriver(driverClassName); |
296 | 0 | Map conData = jdbcMetadataUtils.parseConnectionUrl(url); |
297 | 0 | jcd.setDbms(platform); |
298 | 0 | jcd.setProtocol((String)conData.get(JdbcMetadataUtils.PROPERTY_PROTOCOL)); |
299 | 0 | jcd.setSubProtocol((String)conData.get(JdbcMetadataUtils.PROPERTY_SUBPROTOCOL)); |
300 | 0 | jcd.setDbAlias((String)conData.get(JdbcMetadataUtils.PROPERTY_DBALIAS)); |
301 | 0 | jcd.setUserName(username); |
302 | 0 | jcd.setPassWord(password); |
303 | // Wrapping the connection factory in a DataSource introduces a bit |
|
304 | // of redundancy (url is parsed again and platform determined again). |
|
305 | // But although JdbcMetadataUtils exposes the methods used in |
|
306 | // fillJCDFromDataSource as public (and these do not require a DataSource) |
|
307 | // the method itself does more than is made available by the exposed methods. |
|
308 | // ds = new MinimalDataSource (jcd); |
|
309 | 0 | ds = this; |
310 | } |
|
311 | 0 | ConnectionPoolDescriptor cpd = jcd.getConnectionPoolDescriptor(); |
312 | 0 | if (cpd == null) |
313 | { |
|
314 | 0 | cpd = new ConnectionPoolDescriptor(); |
315 | 0 | jcd.setConnectionPoolDescriptor(cpd); |
316 | } |
|
317 | 0 | Class conFacCls = ClassHelper.getClass(connectionFactoryClass); |
318 | 0 | cpd.setConnectionFactory(conFacCls); |
319 | ||
320 | 0 | jdbcMetadataUtils.fillJCDFromDataSource(jcd, ds, null, class="keyword">null); |
321 | ||
322 | 0 | if (platform == null && JdbcMetadataUtils.PLATFORM_ORACLE.equals(jcd.getDbms())) { |
323 | // Postprocess to find Oracle version. |
|
324 | 0 | updateOraclePlatform (jcd, ds); |
325 | } |
|
326 | // if platform has explicitly been set, the value takes precedence |
|
327 | 0 | if (platform != null) { |
328 | 0 | if (!platform.equals(jcd.getDbms())) { |
329 | 0 | log.warn ("Automatically derived RDBMS platform \"" + jcd.getDbms() |
330 | + "\" differs from explicitly set platform \"" + platform + "\""); |
|
331 | } |
|
332 | 0 | jcd.setDbms(platform); |
333 | } else { |
|
334 | 0 | platform = jcd.getDbms(); |
335 | } |
|
336 | ||
337 | // special attributes |
|
338 | 0 | jcd.addAttribute("org.apache.jetspeed.engineScoped", |
339 | Boolean.toString(jetspeedEngineScoped)); |
|
340 | 0 | } |
341 | ||
342 | /** |
|
343 | * @param jcd |
|
344 | * @throws LookupException |
|
345 | * @throws IllegalAccessException |
|
346 | * @throws InstantiationException |
|
347 | * throws SQLException |
|
348 | */ |
|
349 | private void updateOraclePlatform(JdbcConnectionDescriptor jcd, DataSource ds) |
|
350 | throws LookupException, IllegalAccessException, InstantiationException, SQLException |
|
351 | { |
|
352 | 0 | Connection con = null; |
353 | try |
|
354 | { |
|
355 | 0 | con = ds.getConnection(); |
356 | 0 | DatabaseMetaData metaData = con.getMetaData(); |
357 | 0 | int rdbmsVersion = 0; |
358 | try |
|
359 | { |
|
360 | // getDatabaseMajorVersion exists since 1.4, so it may |
|
361 | // not be defined for the driver used. |
|
362 | 0 | rdbmsVersion = metaData.getDatabaseMajorVersion(); |
363 | 0 | } catch (Throwable t) { |
364 | 0 | String dbVersion = metaData.getDatabaseProductVersion(); |
365 | 0 | String relKey = "Release"; |
366 | 0 | String major = dbVersion; |
367 | 0 | int startPos = dbVersion.indexOf(relKey); |
368 | 0 | if (startPos < 0) |
369 | { |
|
370 | 0 | log.warn ("Cannot determine Oracle version, no \"Release\" in procuct version: \"" + dbVersion + "\""); |
371 | return; |
|
372 | } |
|
373 | 0 | startPos += relKey.length(); |
374 | 0 | int dotPos = dbVersion.indexOf('.', startPos); |
375 | 0 | if (dotPos > 0) { |
376 | 0 | major = dbVersion.substring(startPos, dotPos).trim(); |
377 | } |
|
378 | try |
|
379 | { |
|
380 | 0 | rdbmsVersion = Integer.parseInt(major); |
381 | } |
|
382 | 0 | catch (NumberFormatException e) |
383 | { |
|
384 | 0 | log.warn ("Cannot determine Oracle version, product version \"" + dbVersion + "\" not layed out as \"... Release N.M.....\""); |
385 | return; |
|
386 | 0 | } |
387 | 0 | if (log.isDebugEnabled()) |
388 | { |
|
389 | 0 | log.debug ("Extracted Oracle major version " + rdbmsVersion + " from product version \"" + dbVersion + "\""); |
390 | } |
|
391 | 0 | } |
392 | 0 | if (rdbmsVersion >= 9) { |
393 | 0 | jcd.setDbms(JdbcMetadataUtils.PLATFORM_ORACLE9I); |
394 | } |
|
395 | } |
|
396 | finally |
|
397 | { |
|
398 | 0 | if (con != null) { |
399 | 0 | con.close (); |
400 | } |
|
401 | } |
|
402 | 0 | } |
403 | ||
404 | /** |
|
405 | * a minimal DataSource implementation that satisfies the requirements |
|
406 | * of JdbcMetadataUtil. |
|
407 | */ |
|
408 | private class MinimalDataSource implements DataSource |
|
409 | { |
|
410 | private JdbcConnectionDescriptor jcd = null; |
|
411 | ||
412 | /** |
|
413 | * Create a new instance using the given JCD. |
|
414 | */ |
|
415 | public MinimalDataSource (JdbcConnectionDescriptor jcd) |
|
416 | { |
|
417 | this.jcd = jcd; |
|
418 | } |
|
419 | ||
420 | /* (non-Javadoc) |
|
421 | * @see javax.sql.DataSource#getConnection() |
|
422 | */ |
|
423 | public Connection getConnection() throws SQLException { |
|
424 | // Use JDBC DriverManager as we may not rely on JCD to be sufficiently |
|
425 | // initialized to use any of the ConnectionFactories. |
|
426 | try { |
|
427 | // loads the driver - NB call to newInstance() added to force initialisation |
|
428 | ClassHelper.getClass(jcd.getDriver(), true); |
|
429 | String url = jcd.getProtocol() + ":" + jcd.getSubProtocol() + ":" + jcd.getDbAlias(); |
|
430 | if (jcd.getUserName() == null) |
|
431 | { |
|
432 | return DriverManager.getConnection(url); |
|
433 | } |
|
434 | else |
|
435 | { |
|
436 | return DriverManager.getConnection(url, jcd.getUserName(), jcd.getPassWord()); |
|
437 | } |
|
438 | } |
|
439 | catch (ClassNotFoundException e) |
|
440 | { |
|
441 | throw (IllegalStateException) |
|
442 | (new IllegalStateException (e.getMessage ())).initCause (e); |
|
443 | } |
|
444 | } |
|
445 | ||
446 | /** |
|
447 | * @see javax.sql.DataSource#getConnection(java.lang.String, java.lang.String) |
|
448 | */ |
|
449 | public Connection getConnection(String username, String password) |
|
450 | throws SQLException { |
|
451 | return getConnection (); |
|
452 | } |
|
453 | ||
454 | /** |
|
455 | * @see javax.sql.DataSource#getLoginTimeout() |
|
456 | */ |
|
457 | public int getLoginTimeout() throws SQLException |
|
458 | { |
|
459 | return 0; |
|
460 | } |
|
461 | ||
462 | /** |
|
463 | * @see javax.sql.DataSource#getLogWriter() |
|
464 | */ |
|
465 | public PrintWriter getLogWriter() throws SQLException { |
|
466 | return null; |
|
467 | } |
|
468 | ||
469 | /** |
|
470 | * @see javax.sql.DataSource#setLoginTimeout(int) |
|
471 | */ |
|
472 | public void setLoginTimeout(int seconds) throws SQLException { |
|
473 | } |
|
474 | ||
475 | /** |
|
476 | * @see javax.sql.DataSource#setLogWriter(java.io.PrintWriter) |
|
477 | */ |
|
478 | public void setLogWriter(PrintWriter out) throws SQLException { |
|
479 | } |
|
480 | } |
|
481 | ||
482 | } |
This report is generated by jcoverage, Maven and Maven JCoverage Plugin. |