001: /*
002: * Copyright (c) 1998 - 2005 Versant Corporation
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * Versant Corporation - initial API and implementation
010: */
011: package com.versant.core.jdbc;
012:
013: import com.versant.core.storagemanager.*;
014: import com.versant.core.logging.LogEventStore;
015: import com.versant.core.metadata.ModelMetaData;
016: import com.versant.core.metadata.ClassMetaData;
017:
018: import com.versant.core.metadata.generator.OIDSrcGenerator;
019: import com.versant.core.metadata.generator.StateSrcGenerator;
020:
021: import com.versant.core.common.config.ConfigInfo;
022: import com.versant.core.common.*;
023: import com.versant.core.jdbc.sql.SqlDriver;
024: import com.versant.core.jdbc.conn.JDBCConnectionPool;
025: import com.versant.core.jdbc.metadata.JdbcMetaData;
026: import com.versant.core.jdbc.metadata.JdbcClass;
027: import com.versant.core.server.DataStoreInfo;
028: import com.versant.core.server.CompiledQueryCache;
029: import com.versant.core.metric.HasMetrics;
030:
031: import com.versant.core.compiler.ClassSpec;
032:
033: import java.util.*;
034: import java.sql.Driver;
035: import java.sql.Connection;
036: import java.sql.SQLException;
037: import java.lang.reflect.Constructor;
038: import java.io.IOException;
039:
040: /**
041: * Creates JdbcStorageManager's.
042: */
043: public final class JdbcStorageManagerFactory implements
044: StorageManagerFactory, HasMetrics {
045:
046: private final LogEventStore pes;
047: private final StorageCache cache;
048: private JdbcConnectionSource conSrc;
049: private final ModelMetaData jmd;
050: private final JdbcConfig jdbcConfig;
051: private final SqlDriver sqlDriver;
052: private final CompiledQueryCache compiledQueryCache;
053: private final boolean hyperdrive;
054: private Driver jdbcDriver;
055:
056: public JdbcStorageManagerFactory(StorageManagerFactoryBuilder b) {
057: this .pes = b.getLogEventStore();
058: this .cache = b.getCache();
059: this .compiledQueryCache = b.getCompiledQueryCache();
060: ConfigInfo config = b.getConfig();
061: this .jdbcConfig = new JdbcConfigParser().parse(config.props);
062:
063: boolean createPool = !b.isOnlyMetaData();
064: ClassLoader loader = b.getLoader();
065:
066: // load JDBC driver, create wrapper and conSrc + customize wrapper
067: if (createPool) {
068: jdbcDriver = SqlDriver.createJdbcDriver(jdbcConfig.driver,
069: loader);
070: } else {
071: jdbcDriver = null;
072: }
073: sqlDriver = SqlDriver
074: .createSqlDriver(jdbcConfig.db, jdbcDriver);
075: if (createPool) {
076: createPool(loader);
077: } else {
078: conSrc = null;
079: }
080:
081: // build meta data
082: JdbcMetaDataBuilder mdb = new JdbcMetaDataBuilder(config,
083: jdbcConfig, loader, sqlDriver, b
084: .isContinueAfterMetaDataError());
085: jmd = mdb.buildMetaData(config.jdoMetaData);
086:
087: // generate source for hyperdrive classes if needed
088: hyperdrive = config.hyperdrive;
089:
090: if (hyperdrive) {
091: OIDSrcGenerator oidGen = new JdbcOIDGenerator(jmd);
092: StateSrcGenerator stateGen = new JdbcStateGenerator();
093: HashMap classSpecs = b.getClassSpecs();
094: for (int i = jmd.classes.length - 1; i >= 0; i--) {
095: ClassMetaData cmd = jmd.classes[i];
096: if (cmd.horizontal)
097: continue;
098: ClassSpec spec = oidGen.generateOID(cmd);
099: classSpecs.put(spec.getQName(), spec);
100: spec = stateGen.generateState(cmd);
101: classSpecs.put(spec.getQName(), spec);
102: }
103: }
104:
105: }
106:
107: public void init(boolean full, ClassLoader loader) {
108:
109: if (hyperdrive) {
110: if (full) {
111: installHyperdriveStateAndOIDFactory(loader);
112: }
113: } else { // not using generated hyperdrive classes
114: installGenericStateAndOIDFactory();
115: }
116:
117: Connection con = null;
118: try {
119: conSrc.init();
120: if (sqlDriver.isCustomizeForServerRequired()) {
121: con = conSrc.getConnection(false, false);
122: sqlDriver.customizeForServer(con);
123: }
124: if (full) {
125: ClassMetaData[] classes = jmd.classes;
126: for (int j = 0; j < classes.length; j++) {
127: ClassMetaData cmd = classes[j];
128: if (cmd.top != cmd) {
129: continue;
130: }
131: JdbcKeyGenerator kg = ((JdbcClass) cmd.storeClass).jdbcKeyGenerator;
132: if (kg == null) {
133: continue;
134: }
135: if (con == null) {
136: con = conSrc.getConnection(false, false);
137: }
138: kg.init(cmd.qname,
139: ((JdbcClass) cmd.storeClass).table, con);
140: con.commit();
141: }
142: }
143: } catch (SQLException e) {
144: throw BindingSupportImpl.getInstance().datastore(
145: e.toString(), e);
146: } finally {
147: if (con != null) {
148: try {
149: conSrc.returnConnection(con);
150: } catch (SQLException e) {
151: // ignore
152: }
153: }
154: }
155: }
156:
157: /**
158: * Install a single StateAndOIDFactory for all classes that uses hand
159: * written State and OID classes.
160: */
161: private void installGenericStateAndOIDFactory() {
162: StateAndOIDFactory f = new GenericFactory();
163: ClassMetaData[] classes = jmd.classes;
164: for (int i = 0; i < classes.length; i++) {
165: classes[i].stateAndOIDFactory = f;
166: }
167: }
168:
169: /**
170: * Install a StateAndOIDFactory for each class that uses the generated
171: * State and OID classes.
172: */
173:
174: private void installHyperdriveStateAndOIDFactory(ClassLoader loader) {
175: try {
176: ClassMetaData[] classes = jmd.classes;
177: for (int i = 0; i < classes.length; i++) {
178: ClassMetaData cmd = classes[i];
179: if (cmd.horizontal) {
180: continue;
181: }
182: Class oidClass = Class.forName(cmd.oidClassName, true,
183: loader);
184: Class stateClass = Class.forName(cmd.stateClassName,
185: true, loader);
186: if (cmd.isInHeirachy()) {
187: cmd.stateAndOIDFactory = new HyperdriveFactoryHeirachy(
188: oidClass, stateClass);
189: } else {
190: cmd.stateAndOIDFactory = new HyperdriveFactory(
191: oidClass, stateClass);
192: }
193: }
194: } catch (Exception e) {
195: throw BindingSupportImpl.getInstance().internal(
196: e.toString(), e);
197: }
198: }
199:
200: public void destroy() {
201: if (conSrc != null) {
202: conSrc.destroy();
203: }
204: compiledQueryCache.clear();
205: }
206:
207: /**
208: * If we do not have a JdbcConnectionSource then create a connection
209: * pool otherwise do nothing.
210: */
211: public void createPool(ClassLoader loader) {
212: if (conSrc == null) {
213: if (jdbcDriver == null) {
214: jdbcDriver = SqlDriver.createJdbcDriver(
215: jdbcConfig.driver, loader);
216: }
217: conSrc = new JDBCConnectionPool(jdbcConfig, pes,
218: jdbcDriver, sqlDriver);
219: }
220: }
221:
222: public StorageManager getStorageManager() {
223: return new JdbcStorageManager(jmd, conSrc, sqlDriver, cache,
224: compiledQueryCache, pes, jdbcConfig);
225: }
226:
227: public void returnStorageManager(StorageManager sm) {
228: sm.destroy();
229: }
230:
231: public LogEventStore getPerfEventStore() {
232: return pes;
233: }
234:
235: public StorageCache getCache() {
236: return cache;
237: }
238:
239: public JdbcConnectionSource getConnectionSource() {
240: return conSrc;
241: }
242:
243: public ModelMetaData getModelMetaData() {
244: return jmd;
245: }
246:
247: public SqlDriver getSqlDriver() {
248: return sqlDriver;
249: }
250:
251: public JdbcConfig getJdbcConfig() {
252: return jdbcConfig;
253: }
254:
255: public Object getDatastoreConnection() {
256: try {
257: return conSrc.getConnection(false, false);
258: } catch (SQLException e) {
259: throw BindingSupportImpl.getInstance().datastore(
260: e.toString(), e);
261: }
262: }
263:
264: public void closeIdleDatastoreConnections() {
265: conSrc.closeIdleConnections();
266: }
267:
268: public JdbcMetaData getJdbcMetaData() {
269: return (JdbcMetaData) jmd.jdbcMetaData;
270: }
271:
272: public DataStoreInfo getDataStoreInfo() {
273: DataStoreInfo info = new DataStoreInfo();
274: info.setDataStoreType(sqlDriver.getName());
275: info.setName("main");
276: info.setAutoIncSupported(sqlDriver.isAutoIncSupported());
277: info.setJdbc(true);
278: info.setMajorVersion(sqlDriver.getMajorVersion());
279: info.setPreparedStatementPoolingOK(sqlDriver
280: .isPreparedStatementPoolingOK());
281: info.setScrollableResultSetSupported(sqlDriver
282: .isScrollableResultSetSupported());
283: info
284: .setSelectForUpdate(sqlDriver.getSelectForUpdate() == null ? null
285: : new String(sqlDriver.getSelectForUpdate()));
286: return info;
287: }
288:
289: public void addMetrics(List list) {
290: if (conSrc instanceof HasMetrics) {
291: ((HasMetrics) conSrc).addMetrics(list);
292: }
293: if (cache instanceof HasMetrics) {
294: ((HasMetrics) cache).addMetrics(list);
295: }
296: }
297:
298: public void sampleMetrics(int[][] buf, int pos) {
299: if (conSrc instanceof HasMetrics) {
300: ((HasMetrics) conSrc).sampleMetrics(buf, pos);
301: }
302: if (cache instanceof HasMetrics) {
303: ((HasMetrics) cache).sampleMetrics(buf, pos);
304: }
305: }
306:
307: public StorageManagerFactory getInnerStorageManagerFactory() {
308: return null;
309: }
310:
311: public void supportedOptions(Set options) {
312: }
313:
314: public CompiledQueryCache getCompiledQueryCache() {
315: return compiledQueryCache;
316: }
317:
318: /**
319: * Factory that returns instances of the non-generated State and OID
320: * classes.
321: */
322: private static class GenericFactory implements StateAndOIDFactory {
323:
324: public OID createOID(ClassMetaData cmd, boolean resolved) {
325: return new JdbcGenericOID(cmd, resolved);
326: }
327:
328: public State createState(ClassMetaData cmd) {
329: return new JdbcGenericState(cmd);
330: }
331:
332: public NewObjectOID createNewObjectOID(ClassMetaData cmd) {
333: return new JdbcNewObjectOID(cmd);
334: }
335:
336: public OID createUntypedOID() {
337: throw BindingSupportImpl.getInstance().unsupported(
338: "Untyped OIDs are not supported by the datastore");
339: }
340: }
341:
342: /**
343: * Factory for classes not in a hierachy.
344: */
345: private static class HyperdriveFactory implements
346: StateAndOIDFactory {
347:
348: protected final Class stateClass;
349: protected final Class oidClass;
350:
351: public HyperdriveFactory(Class oidClass, Class stateClass) {
352: this .oidClass = oidClass;
353: this .stateClass = stateClass;
354: }
355:
356: public State createState(ClassMetaData cmd) {
357: try {
358: return (State) stateClass.newInstance();
359: } catch (Exception e) {
360: throw BindingSupportImpl.getInstance().internal(
361: e.toString(), e);
362: }
363: }
364:
365: public OID createOID(ClassMetaData cmd, boolean resolved) {
366: try {
367: return (OID) oidClass.newInstance();
368: } catch (Exception e) {
369: throw BindingSupportImpl.getInstance().internal(
370: e.toString(), e);
371: }
372: }
373:
374: public NewObjectOID createNewObjectOID(ClassMetaData cmd) {
375: return new JdbcNewObjectOID(cmd);
376: }
377:
378: public OID createUntypedOID() {
379: throw BindingSupportImpl.getInstance().unsupported(
380: "Untyped OIDs are not supported by the datastore");
381: }
382: }
383:
384: /**
385: * Factory for classes in a heirachy.
386: */
387: private static class HyperdriveFactoryHeirachy extends
388: HyperdriveFactory {
389:
390: private transient Constructor oidCon;
391:
392: public HyperdriveFactoryHeirachy(Class oidClass,
393: Class stateClass) {
394: super (oidClass, stateClass);
395: init();
396: }
397:
398: private void init() {
399: try {
400: oidCon = oidClass.getConstructor(new Class[] {
401: ClassMetaData.class, Boolean.TYPE });
402: } catch (NoSuchMethodException e) {
403: throw BindingSupportImpl.getInstance().internal(
404: e.toString(), e);
405: }
406: }
407:
408: private void writeObject(java.io.ObjectOutputStream out)
409: throws IOException {
410: out.defaultWriteObject();
411: }
412:
413: private void readObject(java.io.ObjectInputStream in)
414: throws IOException, ClassNotFoundException {
415: in.defaultReadObject();
416: init();
417: }
418:
419: public OID createOID(ClassMetaData cmd, boolean resolved) {
420: try {
421: return (OID) oidCon.newInstance(new Object[] { cmd,
422: resolved ? Boolean.TRUE : Boolean.FALSE });
423: } catch (Exception e) {
424: throw BindingSupportImpl.getInstance().internal(
425: e.toString(), e);
426: }
427: }
428: }
429:
430: }
|