1 | /* |
2 | |
3 | Derby - Class org.apache.derby.jdbc.ReferenceableDataSource |
4 | |
5 | Copyright 2003, 2004 The Apache Software Foundation or its licensors, as applicable. |
6 | |
7 | Licensed under the Apache License, Version 2.0 (the "License"); |
8 | you may not use this file except in compliance with the License. |
9 | You may obtain a copy of the License at |
10 | |
11 | http://www.apache.org/licenses/LICENSE-2.0 |
12 | |
13 | Unless required by applicable law or agreed to in writing, software |
14 | distributed under the License is distributed on an "AS IS" BASIS, |
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | See the License for the specific language governing permissions and |
17 | limitations under the License. |
18 | |
19 | */ |
20 | package org.apache.derby.jdbc; |
21 | |
22 | import java.sql.SQLException; |
23 | import java.lang.reflect.*; |
24 | |
25 | |
26 | import java.io.Serializable; |
27 | import java.io.PrintWriter; |
28 | import java.util.Properties; |
29 | |
30 | /* -- JNDI -- */ |
31 | import javax.naming.NamingException; |
32 | import javax.naming.Referenceable; |
33 | import javax.naming.Reference; |
34 | import javax.naming.StringRefAddr; |
35 | import javax.naming.spi.ObjectFactory; |
36 | import javax.naming.Context; |
37 | import javax.naming.Name; |
38 | import javax.naming.Reference; |
39 | import javax.naming.RefAddr; |
40 | import java.util.Hashtable; |
41 | import java.util.Enumeration; |
42 | |
43 | /** |
44 | |
45 | Cloudscape DataSource implementation base class. |
46 | ReferenceableDataSource provides support for JDBC standard DataSource attributes and acts |
47 | as the ObjectFactory to generate Cloudscape DataSource implementations. |
48 | <P> |
49 | The standard attributes provided by this class are: |
50 | <UL> |
51 | <LI>databaseName |
52 | <LI>dataSourceName |
53 | <LI>description |
54 | <LI>password |
55 | <LI>user |
56 | </UL> |
57 | <BR> |
58 | See the specific Cloudscape DataSource implementation for details on their meaning. |
59 | <BR> |
60 | See the JDBC 3.0 specification for more details. |
61 | |
62 | |
63 | */ |
64 | public class ReferenceableDataSource implements |
65 | javax.naming.Referenceable, |
66 | java.io.Serializable, |
67 | ObjectFactory |
68 | { |
69 | |
70 | |
71 | private static final long serialVersionUID = 1872877359127597176L; |
72 | |
73 | |
74 | private static final Class[] STRING_ARG = { "".getClass() }; |
75 | private static final Class[] INT_ARG = { Integer.TYPE }; |
76 | private static final Class[] BOOLEAN_ARG = { Boolean.TYPE }; |
77 | |
78 | private String description; |
79 | private String dataSourceName; |
80 | private String databaseName; |
81 | private String password; |
82 | private String user; |
83 | private int loginTimeout; |
84 | |
85 | |
86 | /** instance variables that will not be serialized */ |
87 | transient private PrintWriter printer; |
88 | |
89 | /** |
90 | No-arg constructor. |
91 | */ |
92 | public ReferenceableDataSource() { |
93 | update(); |
94 | } |
95 | |
96 | |
97 | /* |
98 | * Properties to be seen by Bean - access thru reflection. |
99 | */ |
100 | |
101 | /** |
102 | Set the database name. Setting this property is mandatory. If a |
103 | database named wombat at g:/db needs to be accessed, database name |
104 | should be set to "g:/db/wombat". The database will be booted if it |
105 | is not already running in the system. |
106 | |
107 | @param databaseName the name of the database |
108 | */ |
109 | public final synchronized void setDatabaseName(String databaseName) { |
110 | this.databaseName = databaseName; |
111 | update(); |
112 | } |
113 | public String getDatabaseName() { |
114 | return databaseName; |
115 | } |
116 | |
117 | /** |
118 | Set the data source name. The property is not mandatory. It is used |
119 | for informational purposes only. |
120 | |
121 | @param dsn the name of the data source |
122 | */ |
123 | public final void setDataSourceName(String dsn) { |
124 | dataSourceName = dsn; |
125 | } |
126 | /** @return data source name */ |
127 | public final String getDataSourceName() { |
128 | return dataSourceName; |
129 | } |
130 | |
131 | /** |
132 | Set the data source descripton. This property is not mandatory. |
133 | It is used for informational purposes only. |
134 | |
135 | @param desc the description of the data source |
136 | */ |
137 | public final void setDescription(String desc) { |
138 | description = desc; |
139 | } |
140 | /** @return description */ |
141 | public final String getDescription() { |
142 | return description; |
143 | } |
144 | |
145 | /** |
146 | Set the <code>user</code> property for the data source. |
147 | This is user name for any data source getConnection() call |
148 | that takes no arguments. |
149 | */ |
150 | public final void setUser(String user) { |
151 | this.user = user; |
152 | } |
153 | /** @return user */ |
154 | public final String getUser() { |
155 | return user; |
156 | } |
157 | |
158 | /** |
159 | Set the <code>password</code> property for the data source. |
160 | This is user's password for any data source getConnection() call |
161 | that takes no arguments. |
162 | */ |
163 | public final void setPassword(String password) { |
164 | this.password = password; |
165 | } |
166 | /** @return password */ |
167 | public final String getPassword() { |
168 | return password; |
169 | } |
170 | |
171 | /* |
172 | * DataSource methods |
173 | */ |
174 | |
175 | |
176 | /** |
177 | * Gets the maximum time in seconds that this data source can wait |
178 | * while attempting to connect to a database. A value of zero |
179 | * means that the timeout is the default system timeout |
180 | * if there is one; otherwise it means that there is no timeout. |
181 | * When a data source object is created, the login timeout is |
182 | * initially zero. |
183 | * |
184 | * @return the data source login time limit |
185 | * @exception SQLException if a database access error occurs. |
186 | */ |
187 | public int getLoginTimeout() throws SQLException |
188 | { |
189 | return loginTimeout; |
190 | } |
191 | |
192 | /** |
193 | * Sets the maximum time in seconds that this data source will wait |
194 | * while attempting to connect to a database. A value of zero |
195 | * specifies that the timeout is the default system timeout |
196 | * if there is one; otherwise it specifies that there is no timeout. |
197 | * When a data source object is created, the login timeout is |
198 | * initially zero. |
199 | <P> |
200 | Cloudscape ignores this property. |
201 | * @param seconds the data source login time limit |
202 | * @exception SQLException if a database access error occurs. |
203 | */ |
204 | public void setLoginTimeout(int seconds) throws SQLException |
205 | { |
206 | loginTimeout = seconds; |
207 | } |
208 | |
209 | |
210 | /** |
211 | * Get the log writer for this data source. |
212 | * |
213 | * <p>The log writer is a character output stream to which all logging |
214 | * and tracing messages for this data source object instance will be |
215 | * printed. This includes messages printed by the methods of this |
216 | * object, messages printed by methods of other objects manufactured |
217 | * by this object, and so on. Messages printed to a data source |
218 | * specific log writer are not printed to the log writer associated |
219 | * with the java.sql.Drivermanager class. When a data source object is |
220 | * created the log writer is initially null, in other words, logging |
221 | * is disabled. |
222 | * |
223 | * @return the log writer for this data source, null if disabled |
224 | * @exception SQLException if a database-access error occurs. |
225 | */ |
226 | public PrintWriter getLogWriter() throws SQLException |
227 | { |
228 | return printer; |
229 | } |
230 | |
231 | /** |
232 | * Set the log writer for this data source. |
233 | * |
234 | * <p>The log writer is a character output stream to which all logging |
235 | * and tracing messages for this data source object instance will be |
236 | * printed. This includes messages printed by the methods of this |
237 | * object, messages printed by methods of other objects manufactured |
238 | * by this object, and so on. Messages printed to a data source |
239 | * specific log writer are not printed to the log writer associated |
240 | * with the java.sql.Drivermanager class. When a data source object is |
241 | * created the log writer is initially null, in other words, logging |
242 | * is disabled. |
243 | * |
244 | * @param out the new log writer; to disable, set to null |
245 | * @exception SQLException if a database-access error occurs. |
246 | */ |
247 | public void setLogWriter(PrintWriter out) throws SQLException |
248 | { |
249 | printer = out; |
250 | } |
251 | |
252 | /* |
253 | ** Reference methods etc. |
254 | */ |
255 | |
256 | /* |
257 | * Object Factory method |
258 | */ |
259 | |
260 | /** |
261 | Re-Create Cloudscape datasource given a reference. |
262 | |
263 | @param obj The possibly null object containing location or reference |
264 | information that can be used in creating an object. |
265 | @param name The name of this object relative to nameCtx, or null if no |
266 | name is specified. |
267 | @param nameCtx The context relative to which the name parameter is |
268 | specified, or null if name is relative to the default initial context. |
269 | @param environment The possibly null environment that is used in |
270 | creating the object. |
271 | |
272 | @return One of the Cloudscape datasource object created; null if an |
273 | object cannot be created. |
274 | |
275 | @exception Exception if this object factory encountered an exception |
276 | while attempting to create an object, and no other object factories are |
277 | to be tried. |
278 | */ |
279 | public Object getObjectInstance(Object obj, |
280 | Name name, |
281 | Context nameCtx, |
282 | Hashtable environment) |
283 | throws Exception |
284 | { |
285 | Reference ref = (Reference)obj; |
286 | String classname = ref.getClassName(); |
287 | |
288 | Object ds = Class.forName(classname).newInstance(); |
289 | |
290 | for (Enumeration e = ref.getAll(); e.hasMoreElements(); ) { |
291 | |
292 | RefAddr attribute = (RefAddr) e.nextElement(); |
293 | |
294 | String propertyName = attribute.getType(); |
295 | |
296 | String value = (String) attribute.getContent(); |
297 | |
298 | String methodName = "set" + propertyName.substring(0,1).toUpperCase(java.util.Locale.ENGLISH) + propertyName.substring(1); |
299 | |
300 | Method m; |
301 | |
302 | Object argValue; |
303 | try { |
304 | m = ds.getClass().getMethod(methodName, STRING_ARG); |
305 | argValue = value; |
306 | } catch (NoSuchMethodException nsme) { |
307 | try { |
308 | m = ds.getClass().getMethod(methodName, INT_ARG); |
309 | argValue = Integer.valueOf(value); |
310 | } catch (NoSuchMethodException nsme2) { |
311 | m = ds.getClass().getMethod(methodName, BOOLEAN_ARG); |
312 | argValue = Boolean.valueOf(value); |
313 | } |
314 | } |
315 | m.invoke(ds, new Object[] { argValue }); |
316 | } |
317 | |
318 | return ds; |
319 | } |
320 | |
321 | /** |
322 | Referenceable method. |
323 | |
324 | @exception NamingException cannot find named object |
325 | */ |
326 | public final Reference getReference() throws NamingException |
327 | { |
328 | // These fields will be set by the JNDI server when it decides to |
329 | // materialize a data source. |
330 | Reference ref = new Reference(this.getClass().getName(), |
331 | "org.apache.derby.jdbc.ReferenceableDataSource", |
332 | null); |
333 | |
334 | |
335 | // Look for all the getXXX methods in the class that take no arguments. |
336 | Method[] methods = this.getClass().getMethods(); |
337 | |
338 | for (int i = 0; i < methods.length; i++) { |
339 | |
340 | Method m = methods[i]; |
341 | |
342 | // only look for simple getter methods. |
343 | if (m.getParameterTypes().length != 0) |
344 | continue; |
345 | |
346 | // only non-static methods |
347 | if (Modifier.isStatic(m.getModifiers())) |
348 | continue; |
349 | |
350 | // Only getXXX methods |
351 | String methodName = m.getName(); |
352 | if ((methodName.length() < 5) || !methodName.startsWith("get")) |
353 | continue; |
354 | |
355 | |
356 | |
357 | Class returnType = m.getReturnType(); |
358 | |
359 | if (Integer.TYPE.equals(returnType) || STRING_ARG[0].equals(returnType) || Boolean.TYPE.equals(returnType)) { |
360 | |
361 | // setSomeProperty |
362 | // 01234 |
363 | |
364 | String propertyName = methodName.substring(3,4).toLowerCase(java.util.Locale.ENGLISH).concat(methodName.substring(4)); |
365 | |
366 | try { |
367 | Object ov = m.invoke(this, null); |
368 | |
369 | //Need to check for nullability for all the properties, otherwise |
370 | //rather than null, "null" string gets stored in jndi. |
371 | if (ov != null) { |
372 | ref.add(new StringRefAddr(propertyName, ov.toString())); |
373 | } |
374 | } catch (IllegalAccessException iae) { |
375 | } catch (InvocationTargetException ite) { |
376 | } |
377 | |
378 | |
379 | } |
380 | } |
381 | |
382 | return ref; |
383 | } |
384 | |
385 | |
386 | void update() { |
387 | } |
388 | |
389 | /** |
390 | Return a connection for the Cloudscape family of data source implementations. |
391 | */ |
392 | java.sql.Connection getConnection(String username, String password, boolean requestPassword) throws SQLException { |
393 | return null; |
394 | } |
395 | |
396 | } |