KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cayenne > conf > DriverDataSourceFactory


1 /*****************************************************************
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  ****************************************************************/

19
20 package org.apache.cayenne.conf;
21
22 import java.io.BufferedReader JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.io.InputStream JavaDoc;
25 import java.io.InputStreamReader JavaDoc;
26 import java.net.MalformedURLException JavaDoc;
27 import java.net.URL JavaDoc;
28
29 import javax.sql.DataSource JavaDoc;
30
31 import org.apache.cayenne.ConfigurationException;
32 import org.apache.cayenne.access.ConnectionLogger;
33 import org.apache.cayenne.access.QueryLogger;
34 import org.apache.cayenne.conn.DataSourceInfo;
35 import org.apache.cayenne.conn.PoolManager;
36 import org.apache.cayenne.util.Util;
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39 import org.xml.sax.Attributes JavaDoc;
40 import org.xml.sax.ContentHandler JavaDoc;
41 import org.xml.sax.InputSource JavaDoc;
42 import org.xml.sax.SAXException JavaDoc;
43 import org.xml.sax.XMLReader JavaDoc;
44 import org.xml.sax.helpers.DefaultHandler JavaDoc;
45
46 /**
47  * Creates DataSource objects from XML configuration files that describe a JDBC driver.
48  * Wraps JDBC driver in a generic DataSource implementation.
49  *
50  * @author Andrus Adamchik
51  */

52 // TODO: factory shouldn't contain any state specific to location ("driverInfo" ivar
53
// should go, and probably "parser" too)... Otherwise the API doesn't make sense -
54
// sequential invocations of getDataSource() will have side effects....
55
public class DriverDataSourceFactory implements DataSourceFactory {
56
57     private static final Log logger = LogFactory.getLog(DriverDataSourceFactory.class);
58
59     protected XMLReader JavaDoc parser;
60     protected DataSourceInfo driverInfo;
61     protected Configuration parentConfiguration;
62
63     /**
64      * Creates new DriverDataSourceFactory.
65      */

66     public DriverDataSourceFactory() throws Exception JavaDoc {
67         this.parser = Util.createXmlReader();
68     }
69
70     /**
71      * Stores configuration object internally to use it later for resource loading.
72      */

73     public void initializeWithParentConfiguration(Configuration parentConfiguration) {
74         this.parentConfiguration = parentConfiguration;
75     }
76
77     public DataSource JavaDoc getDataSource(String JavaDoc location) throws Exception JavaDoc {
78         this.load(location);
79
80         ConnectionLogger logger = new ConnectionLogger();
81
82         try {
83             return new PoolManager(driverInfo.getJdbcDriver(), driverInfo
84                     .getDataSourceUrl(), driverInfo.getMinConnections(), driverInfo
85                     .getMaxConnections(), driverInfo.getUserName(), driverInfo
86                     .getPassword(), logger);
87         }
88         catch (Exception JavaDoc ex) {
89             QueryLogger.logConnectFailure(ex);
90             throw ex;
91         }
92     }
93
94     /**
95      * Returns DataSourceInfo property.
96      */

97     protected DataSourceInfo getDriverInfo() {
98         return this.driverInfo;
99     }
100
101     protected InputStream JavaDoc getInputStream(String JavaDoc location) {
102         if (this.parentConfiguration == null) {
103             throw new ConfigurationException(
104                     "No parent Configuration set - cannot continue.");
105         }
106
107         return this.parentConfiguration.getResourceLocator().findResourceStream(location);
108     }
109
110     /**
111      * Loads driver information from the file at <code>location</code>. Called
112      * internally from "getDataSource"
113      */

114     protected void load(String JavaDoc location) throws Exception JavaDoc {
115         logger.info("loading driver information from '" + location + "'.");
116
117         InputStream JavaDoc in = this.getInputStream(location);
118         if (in == null) {
119             logger.info("Error: location '" + location + "' not found.");
120             throw new ConfigurationException(
121                     "Can't find DataSource configuration file at " + location);
122         }
123
124         RootHandler handler = new RootHandler();
125         parser.setContentHandler(handler);
126         parser.setErrorHandler(handler);
127         parser.parse(new InputSource JavaDoc(in));
128     }
129
130     // SAX handlers start below
131

132     /** Handler for the root element. Its only child must be the "driver" element. */
133     private class RootHandler extends DefaultHandler JavaDoc {
134
135         /**
136          * Handles the start of a "driver" element. A driver handler is created and
137          * initialized with the element name and attributes.
138          *
139          * @exception SAXException if the tag given is not <code>"driver"</code>
140          */

141         public void startElement(
142                 String JavaDoc namespaceURI,
143                 String JavaDoc localName,
144                 String JavaDoc qName,
145                 Attributes JavaDoc atts) throws SAXException JavaDoc {
146             if (localName.equals("driver")) {
147                 new DriverHandler(parser, this).init(localName, atts);
148             }
149             else {
150                 logger.info("<driver> must be the root element. <"
151                         + localName
152                         + "> is unexpected.");
153                 throw new SAXException JavaDoc("Config file is not of expected XML type. '"
154                         + localName
155                         + "' unexpected.");
156             }
157         }
158     }
159
160     /** Handler for the "driver" element. */
161     private class DriverHandler extends AbstractHandler {
162
163         public DriverHandler(XMLReader JavaDoc parser, ContentHandler JavaDoc parentHandler) {
164             super(parser, parentHandler);
165         }
166
167         public void init(String JavaDoc name, Attributes JavaDoc attrs) {
168             String JavaDoc className = attrs.getValue("", "class");
169             logger.info("loading driver " + className);
170             driverInfo = new DataSourceInfo();
171             driverInfo.setJdbcDriver(className);
172         }
173
174         /**
175          * Handles the start of a driver child element. An appropriate handler is created
176          * and initialized with the element name and attributes.
177          *
178          * @exception SAXException if the tag given is not recognized.
179          */

180         public void startElement(
181                 String JavaDoc namespaceURI,
182                 String JavaDoc localName,
183                 String JavaDoc qName,
184                 Attributes JavaDoc atts) throws SAXException JavaDoc {
185             if (localName.equals("login")) {
186                 new LoginHandler(this.parser, this).init(localName, atts, driverInfo);
187             }
188             else if (localName.equals("url")) {
189                 new UrlHandler(this.parser, this).init(localName, atts, driverInfo);
190             }
191             else if (localName.equals("connectionPool")) {
192                 new ConnectionHandler(this.parser, this)
193                         .init(localName, atts, driverInfo);
194             }
195             else {
196                 logger.info("<login, url, connectionPool> are valid. <"
197                         + localName
198                         + "> is unexpected.");
199                 throw new SAXException JavaDoc("Config file is not of expected XML type");
200             }
201         }
202
203     }
204
205     private class UrlHandler extends AbstractHandler {
206
207         /**
208          * Constructor which just delegates to the superconstructor.
209          *
210          * @param parentHandler The handler which should be restored to the parser at the
211          * end of the element. Must not be <code>null</code>.
212          */

213         public UrlHandler(XMLReader JavaDoc parser, ContentHandler JavaDoc parentHandler) {
214             super(parser, parentHandler);
215         }
216
217         public void init(String JavaDoc name, Attributes JavaDoc atts, DataSourceInfo driverInfo)
218                 throws SAXException JavaDoc {
219             driverInfo.setDataSourceUrl(atts.getValue("value"));
220             if (driverInfo.getDataSourceUrl() == null) {
221                 logger.info("error: <url> has no 'value'.");
222                 throw new SAXException JavaDoc("'<url value=' attribute is required.");
223             }
224         }
225     }
226
227     private class LoginHandler extends AbstractHandler {
228
229         /**
230          * Constructor which just delegates to the superconstructor.
231          *
232          * @param parentHandler The handler which should be restored to the parser at the
233          * end of the element. Must not be <code>null</code>.
234          */

235         public LoginHandler(XMLReader JavaDoc parser, ContentHandler JavaDoc parentHandler) {
236             super(parser, parentHandler);
237         }
238
239         private String JavaDoc passwordFromInputStream(InputStream JavaDoc inputStream) {
240             BufferedReader JavaDoc bufferedReader = null;
241             InputStreamReader JavaDoc inputStreamReader = null;
242             String JavaDoc password = null;
243
244             try {
245                 inputStreamReader = new InputStreamReader JavaDoc(inputStream);
246                 bufferedReader = new BufferedReader JavaDoc(inputStreamReader);
247                 password = bufferedReader.readLine();
248             }
249             catch (IOException JavaDoc exception) {
250                 exception.printStackTrace();
251             }
252             finally {
253                 try {
254                     bufferedReader.close();
255                 }
256                 catch (Exception JavaDoc exception) {
257                 }
258
259                 try {
260                     inputStreamReader.close();
261                 }
262                 catch (Exception JavaDoc exception) {
263                 }
264
265                 try {
266                     inputStream.close();
267                 }
268                 catch (IOException JavaDoc exception) {
269                 }
270             }
271
272             return password;
273         }
274
275         private String JavaDoc passwordFromURL(URL JavaDoc url) {
276             InputStream JavaDoc inputStream = null;
277             String JavaDoc password = null;
278
279             try {
280                 inputStream = url.openStream();
281                 password = passwordFromInputStream(inputStream);
282             }
283             catch (IOException JavaDoc exception) {
284                 // Log the error while trying to open the stream. A null
285
// password will be returned as a result.
286
exception.printStackTrace();
287             }
288
289             return password;
290         }
291
292         public void init(String JavaDoc name, Attributes JavaDoc atts, DataSourceInfo driverInfo) {
293             logger.info("loading user name and password.");
294
295             String JavaDoc encoderClass = atts.getValue("encoderClass");
296             String JavaDoc encoderSalt = atts.getValue("encoderSalt");
297             String JavaDoc password = atts.getValue("password");
298             String JavaDoc passwordLocation = atts.getValue("passwordLocation");
299             String JavaDoc passwordSource = atts.getValue("passwordSource");
300             String JavaDoc username = atts.getValue("userName");
301
302             driverInfo.setPasswordEncoderClass(encoderClass);
303             driverInfo.setPasswordEncoderSalt(encoderSalt);
304             driverInfo.setPasswordLocation(passwordLocation);
305             driverInfo.setPasswordSource(passwordSource);
306             driverInfo.setUserName(username);
307
308             // Replace {} in passwordSource with encoderSalt -- useful for EXECUTABLE &
309
// URL options
310
if (encoderSalt != null) {
311                 passwordSource = passwordSource.replaceAll("\\{\\}", encoderSalt);
312             }
313
314             PasswordEncoding passwordEncoder = driverInfo.getPasswordEncoder();
315
316             if (passwordLocation != null) // New style model (v1.2), process extra
317
// locations
318
{
319                 if (passwordLocation.equals(DataSourceInfo.PASSWORD_LOCATION_CLASSPATH)) {
320                     URL JavaDoc url = parentConfiguration.getResourceLocator().findResource(
321                             passwordSource);
322
323                     if (url != null)
324                         password = passwordFromURL(url);
325                     else
326                         logger.error("Could not find resource in CLASSPATH: "
327                                 + passwordSource);
328                 }
329                 else if (passwordLocation.equals(DataSourceInfo.PASSWORD_LOCATION_URL)) {
330                     try {
331                         password = passwordFromURL(new URL JavaDoc(passwordSource));
332                     }
333                     catch (MalformedURLException JavaDoc exception) {
334                         exception.printStackTrace();
335                     }
336                 }
337                 else if (passwordLocation
338                         .equals(DataSourceInfo.PASSWORD_LOCATION_EXECUTABLE)) {
339                     if (passwordSource != null) {
340                         try {
341                             Process JavaDoc process = Runtime.getRuntime().exec(passwordSource);
342                             password = passwordFromInputStream(process.getInputStream());
343                             process.waitFor();
344                         }
345                         catch (IOException JavaDoc exception) {
346                             exception.printStackTrace();
347                         }
348                         catch (InterruptedException JavaDoc exception) {
349                             exception.printStackTrace();
350                         }
351                     }
352                 }
353             }
354
355             if (password != null && passwordEncoder != null)
356                 driverInfo.setPassword(passwordEncoder.decodePassword(
357                         password,
358                         encoderSalt));
359         }
360     }
361
362     private class ConnectionHandler extends AbstractHandler {
363
364         /**
365          * Constructor which just delegates to the superconstructor.
366          *
367          * @param parentHandler The handler which should be restored to the parser at the
368          * end of the element. Must not be <code>null</code>.
369          */

370         public ConnectionHandler(XMLReader JavaDoc parser, ContentHandler JavaDoc parentHandler) {
371             super(parser, parentHandler);
372         }
373
374         public void init(String JavaDoc name, Attributes JavaDoc atts, DataSourceInfo driverInfo)
375                 throws SAXException JavaDoc {
376             try {
377                 String JavaDoc min = atts.getValue("min");
378                 if (min != null)
379                     driverInfo.setMinConnections(Integer.parseInt(min));
380
381                 String JavaDoc max = atts.getValue("max");
382                 if (max != null)
383                     driverInfo.setMaxConnections(Integer.parseInt(max));
384             }
385             catch (NumberFormatException JavaDoc nfex) {
386                 logger.info("Error loading numeric attribute", nfex);
387                 throw new SAXException JavaDoc("Error reading numeric attribute.", nfex);
388             }
389         }
390     }
391 }
392
Popular Tags