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