Source code: org/enableit/db/daf/castor/JdoFactory.java
1 package org.enableit.db.daf.castor;
2
3 import java.io.PrintWriter;
4 import java.sql.*;
5 import java.util.*;
6
7 import javax.naming.InitialContext;
8 import javax.sql.DataSource;
9
10 import org.exolab.castor.jdo.JDO;
11 import org.exolab.castor.jdo.Database;
12 import org.exolab.castor.jdo.OQLQuery;
13 import org.exolab.castor.jdo.QueryResults;
14 import org.exolab.castor.mapping.Mapping;
15 import org.exolab.castor.mapping.MappingResolver;
16 import org.exolab.castor.mapping.FieldDescriptor;
17 import org.exolab.castor.util.Logger;
18
19 // Log4J imports
20 import org.apache.log4j.Category;
21
22 /**
23 * Factory pattern for creating connections to a JDO managed datasource.
24 * <br>
25 * This class is final to prevent a breach of security by subclassing.
26 * <br>
27 * The JDO implementation is Castor from
28 * <a href="http://castor.exolab.org/">exolab.org</a>.
29 */
30 public final class JdoFactory
31 {
32 private static Mapping mapping;
33 private static JDO jdo;
34
35 private static String databaseName = "dev";
36 public static final String DATABASE_FILE = "database.xml";
37 public static final String DATABASE_WITHOUT_CONTAINER_FILE = "database-without-container.xml";
38 public static final String MAPPING_FILE = "mapping.xml";
39
40 /**
41 * Define a static Category instance for logging
42 * Use one per package
43 */
44 private static Category logger = Category.getInstance(JdoFactory.class);
45
46
47 /**
48 * Sets the database name to be used and resets the internal JDO reference.
49 * This is useful if either the mapping or database configuration files
50 * has been changed.
51 */
52 public static void setDatabaseName(String newDatabaseName)
53 {
54 logger.info("METHOD_ENTRY: setDatabaseName" ) ;
55
56 databaseName = newDatabaseName ;
57
58 // reset mapping and jdo in case the config file was actually changed
59 mapping = null ;
60 jdo = null ;
61
62 logger.info("METHOD_EXIT: setDatabaseName" ) ;
63 }
64
65 /**
66 * Get a JDO object.
67 * This is analogous to a JDBC 2 DataSource.
68 */
69 public static final JDO getJdo()
70 {
71 logger.info("METHOD_ENTRY: getJdo" ) ;
72
73 try {
74 // Load the mapping file
75 if (mapping==null) {
76 logger.debug("configuring new mapping") ;
77 mapping = new Mapping( JdoFactory.class.getClassLoader() );
78 logger.debug("... instantiated ok") ;
79 // uncomment the following line to debug JDO
80 mapping.setLogWriter( Logger.getSystemLogger() );
81 mapping.loadMapping( JdoFactory.class.getResource( MAPPING_FILE ) );
82 logger.debug("... mapping config file loaded ok") ;
83 }
84
85 if (jdo==null) {
86 logger.debug("configuring new JDO") ;
87 jdo = new JDO();
88 // uncomment the following line to debug JDO
89 jdo.setLogWriter(Logger.getSystemLogger());
90 jdo.setConfiguration( JdoFactory.class.getResource( DATABASE_FILE ).toString() );
91 logger.debug("... database config file loaded ok") ;
92 jdo.setDatabaseName( databaseName );
93 logger.debug("... database set to '" + databaseName + "'") ;
94 }
95
96 } catch (java.io.IOException e) {
97 logger.fatal(e.getMessage()) ;
98 logger.fatal(e) ;
99 throw new RuntimeException(e.getMessage()) ;
100 } catch (org.exolab.castor.mapping.MappingException e) {
101 logger.fatal(e.getMessage()) ;
102 logger.fatal(e) ;
103 throw new RuntimeException(e.getMessage()) ;
104 }
105
106 logger.info("METHOD_ENTRY: getJdo" ) ;
107 return jdo ;
108 }
109
110 /**
111 * Get a JDO Database object.
112 * This is analogous to a JDBC Connection.
113 */
114 public static final Database getDatabase()
115 {
116 logger.info("METHOD_ENTRY: getDatabase" ) ;
117
118 Database database = null ;
119 try {
120 database = getJdo().getDatabase() ;
121 } catch (org.exolab.castor.jdo.DatabaseNotFoundException e) {
122 if (e.getMessage().startsWith("Nested error: javax.naming")) {
123 // Assume running outside container and attempt config appropriately
124 try {
125 logger.debug("configuring new JDO outside a J2EE container") ;
126 jdo = new JDO();
127 // uncomment the following line to debug JDO
128 //jdo.setLogWriter(Logger.getSystemLogger());
129 jdo.setConfiguration( JdoFactory.class.getResource( DATABASE_WITHOUT_CONTAINER_FILE ).toString() );
130 logger.debug("... database config file loaded ok") ;
131 jdo.setDatabaseName( databaseName );
132 logger.warn("... database set to '" + databaseName + "'") ;
133 database = jdo.getDatabase() ;
134 } catch (Exception e2) {
135 // We are probably dealing with a development time error now
136 System.err.println("ERROR: " + e2.getClass().getName()) ;
137 System.err.println("ERROR: " + e2.getMessage()) ;
138 logger.fatal(e.getMessage()) ;
139 logger.fatal(e) ;
140 throw new RuntimeException(e2.getMessage()) ;
141 }
142 } else {
143 logger.fatal(e.getMessage()) ;
144 logger.fatal(e) ;
145 throw new RuntimeException(e.getMessage()) ;
146 }
147 } catch (org.exolab.castor.jdo.PersistenceException e) {
148 logger.fatal(e.getMessage()) ;
149 logger.fatal(e) ;
150 throw new RuntimeException(e.getMessage()) ;
151 }
152
153 logger.info("METHOD_EXIT: getDatabase" ) ;
154 return database ;
155 }
156
157 /**
158 * Get the property name that holds the database key.
159 */
160 public static String getIdentity(Class clazz)
161 {
162 logger.info("METHOD_ENTRY: getIdentity");
163
164 String keyField = null ;
165 try {
166 MappingResolver resolver = mapping.getResolver(Mapping.JDO) ;
167 FieldDescriptor identityDescriptor = resolver.getDescriptor(clazz).getIdentity() ;
168
169 if (identityDescriptor!=null) {
170 keyField = identityDescriptor.getFieldName() ;
171 }
172 } catch (org.exolab.castor.mapping.MappingException e) {
173 logger.error(e.getClass().getName() + ":" + e.getMessage()) ;
174 // continue and hope for the best, probably a development time prob
175 }
176
177 logger.info("METHOD_EXIT: getIdentity");
178 logger.info("... with params keyField=" + keyField) ;
179 return keyField ;
180 }
181
182 /**
183 * Return a standard JDBC connection, nothing to do with JDO.
184 */
185 public static final Connection getConnection()
186 {
187 logger.info("METHOD_ENTRY: getConnection" ) ;
188
189 Connection conn = null ;
190 try {
191 InitialContext ic = new InitialContext() ;
192 javax.naming.Context envContext = (javax.naming.Context)ic.lookup("java:comp/env");
193 DataSource ds = (DataSource)envContext.lookup("jdbc/DefaultDS") ;
194
195 conn = ds.getConnection() ;
196 if (conn==null) {
197 throw new SQLException("DataSource returned null connection.") ;
198 }
199 } catch (javax.naming.NamingException e) {
200 /*
201 * Assume this is because we are not running in a J2EE container
202 * Try to get a Connection another way
203 */
204
205 // TODO , implement a connection factory
206 if (conn==null) {
207 throw new RuntimeException("have null connection: " +
208 e.getMessage()) ;
209 }
210 } catch (java.sql.SQLException e) {
211 logger.fatal(e.getMessage()) ;
212 logger.fatal(e) ;
213 throw new RuntimeException(e.getMessage()) ;
214 }
215
216 logger.info("METHOD_EXIT: getConnection" ) ;
217 return conn ;
218 }
219 }
220