1 /***
2 * @(#) DataSourceFactory.java
3 *
4 * JFoxSOAF, Service-Oriented Application Framework
5 *
6 * Copyright(c) JFoxSOAF Team
7 *
8 * Licensed under the GNU LGPL, Version 2.1 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.gnu.org/copyleft/lesser.html
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 * For more information, please visit:
21 * http://www.jfox.cn/confluence/display/JFoxSOAF/Home
22 * http://www.huihoo.org/jfox/jfoxsoaf
23 */
24
25 package org.huihoo.jfox.soaf.services.jdbc;
26
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.security.AccessController;
30 import java.security.PrivilegedAction;
31 import java.sql.SQLException;
32 import java.util.Enumeration;
33 import java.util.Hashtable;
34 import java.util.Properties;
35
36 import javax.sql.DataSource;
37
38 import org.huihoo.jfox.soaf.exception.DataSourceConfigurationException;
39 import org.huihoo.jfox.soaf.util.resource.ResourceHelper;
40
41 /***
42 * <p>
43 * Factory for creating database connection instances, with discovery and
44 * configuration features
45 * </p>
46 *
47 * @author <a href="mailto:founder_chen@yahoo.com.cn">Peter Cheng </a>
48 * @version $Revision: 1.6 $ $Date: 2005/05/22 06:49:48 $
49 * @version Revision: 1.0
50 */
51
52 public abstract class DataSourceFactory {
53
54 /***
55 * Protected constructor that is not available for public use.
56 */
57 protected DataSourceFactory() {
58 }
59
60 /***
61 * The previously constructed <code>LogFactory</code> instances, keyed by
62 * the <code>ClassLoader</code> with which it was created.
63 */
64 protected static Hashtable factories = new Hashtable();
65
66 /***
67 * Get singlton database connection instance.
68 */
69 public abstract DataSource getInstance()
70 throws DataSourceConfigurationException, SQLException;
71
72 /***
73 * Return the configuration attribute with the specified name (if any), or
74 * <code>null</code> if there is no such attribute.
75 *
76 * @param name Name of the attribute to return
77 */
78 public abstract Object getAttribute(String name);
79
80 /***
81 * Return an array containing the names of all currently defined
82 * configuration attributes. If there are no such attributes, a zero length
83 * array is returned.
84 */
85 public abstract String[] getAttributeNames();
86
87 /***
88 * Remove any configuration attribute associated with the specified name. If
89 * there is no such attribute, no action is taken.
90 *
91 * @param name Name of the attribute to remove
92 */
93 public abstract void removeAttribute(String name);
94
95 /***
96 * Set the configuration attribute with the specified name. Calling this
97 * with a <code>null</code> value is equivalent to calling
98 * <code>removeAttribute(name)</code>.
99 *
100 * @param name Name of the attribute to set
101 * @param value Value of the attribute to set, or <code>null</code> to
102 * remove any setting for this attribute
103 */
104 public abstract void setAttribute(String name, Object value);
105
106 public static DataSourceFactory getFactory()
107 throws DataSourceConfigurationException {
108
109 DataSourceFactory factory = getCachedFactory(DataSourceFactory.class
110 .getClassLoader());
111
112 if (factory != null) {
113 return factory;
114 }
115
116
117 Properties props = null;
118 try {
119 InputStream stream = ResourceHelper
120 .getResourceAsStream(DatabaseConstant.JDBC_FACTORY_PROPERTIES);
121
122 if (stream != null) {
123 props = new Properties();
124 props.load(stream);
125 stream.close();
126 }
127 } catch (IOException e) {
128 throw new DataSourceConfigurationException(
129 "Load Database configuration IO exception " + e);
130 } catch (SecurityException e) {
131 throw new DataSourceConfigurationException(
132 "Database configuration access security exception " + e);
133 }
134
135
136 if (factory == null && props != null) {
137 String factoryClass = props
138 .getProperty(DatabaseConstant.JDBC_DATABASE_FACTORY);
139 if (factoryClass != null && !factoryClass.equals("")) {
140 factory = newFactory(factoryClass, DataSourceFactory.class
141 .getClassLoader());
142 }
143 }
144
145
146 if (factory == null) {
147 factory = newFactory(DatabaseConstant.JDBC_DEFAULT_FACTORY,
148 DataSourceFactory.class.getClassLoader());
149 }
150
151 if (factory != null) {
152 /***
153 * Always cache using context class loader..
154 */
155 cacheFactory(DataSourceFactory.class.getClassLoader(), factory);
156
157 if (props != null) {
158 Enumeration names = props.propertyNames();
159 while (names.hasMoreElements()) {
160 String name = (String) names.nextElement();
161 String value = props.getProperty(name);
162 factory.setAttribute(name, value);
163 }
164 }
165 }
166
167 return factory;
168 }
169
170 /***
171 * Check cached factories (keyed by classLoader)
172 */
173 private static DataSourceFactory getCachedFactory(
174 ClassLoader contextClassLoader) {
175 DataSourceFactory factory = null;
176
177 if (contextClassLoader != null) {
178 factory = (DataSourceFactory) factories.get(contextClassLoader);
179 }
180
181 return factory;
182 }
183
184 private static void cacheFactory(ClassLoader classLoader,
185 DataSourceFactory factory) {
186 if (classLoader != null && factory != null) {
187 factories.put(classLoader, factory);
188 }
189 }
190
191 /***
192 * Return a new instance of the specified <code>LogFactory</code>
193 * implementation class, loaded by the specified class loader. If that
194 * fails, try the class loader used to load this (abstract) LogFactory.
195 *
196 * @param factoryClass Fully qualified name of the <code>LogFactory</code>
197 * implementation class
198 * @param classLoader ClassLoader from which to load this class
199 * @exception DataSourceConfigException if a suitable instance cannot be
200 * created
201 */
202 protected static DataSourceFactory newFactory(final String factoryClass,
203 final ClassLoader classLoader)
204 throws DataSourceConfigurationException {
205 Object result = AccessController.doPrivileged(new PrivilegedAction() {
206
207 public Object run() {
208 try {
209 if (classLoader != null) {
210 try {
211 return classLoader.loadClass(factoryClass)
212 .newInstance();
213 } catch (ClassNotFoundException ex) {
214 if (classLoader == DataSourceFactory.class
215 .getClassLoader()) {
216
217 throw ex;
218 }
219
220 } catch (NoClassDefFoundError e) {
221 if (classLoader == DataSourceFactory.class
222 .getClassLoader()) {
223 throw e;
224 }
225
226 } catch (ClassCastException e) {
227
228 if (classLoader == DataSourceFactory.class
229 .getClassLoader()) {
230 throw e;
231 }
232 }
233 }
234 return Class.forName(factoryClass).newInstance();
235 } catch (Exception e) {
236 return new DataSourceConfigurationException(e);
237 }
238 }
239 });
240
241 if (result instanceof DataSourceConfigurationException) {
242 throw (DataSourceConfigurationException) result;
243 }
244
245 return (DataSourceFactory) result;
246 }
247
248 /***
249 * Retrive concreate datasource.
250 *
251 * @return PoolDataSource
252 * @throws DataSourceConfigurationException
253 */
254 public static DataSource getDataSource()
255 throws DataSourceConfigurationException {
256 try {
257 return getFactory().getInstance();
258 } catch (Exception e) {
259 throw new DataSourceConfigurationException(e.getMessage(), e);
260 }
261 }
262
263 }