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.jdo;
012:
013: import com.versant.core.common.BindingSupportImpl;
014: import com.versant.core.common.Debug;
015: import com.versant.core.common.OID;
016: import com.versant.core.metadata.ModelMetaData;
017: import com.versant.core.metadata.MDStatics;
018: import com.versant.core.metadata.ClassMetaData;
019: import com.versant.core.util.BeanUtils;
020: import com.versant.core.util.WeakBag;
021: import com.versant.core.common.config.ConfigParser;
022: import com.versant.core.common.config.ConfigInfo;
023: import com.versant.core.logging.LogEvent;
024: import com.versant.core.logging.LogEventStore;
025: import com.versant.core.metric.Metric;
026: import com.versant.core.metric.MetricSnapshotPacket;
027: import com.versant.core.server.DataStoreInfo;
028: import com.versant.core.jdo.query.mem.MemQueryCompiler;
029: import com.versant.core.storagemanager.*;
030:
031: import javax.jdo.PersistenceManager;
032: import javax.jdo.PersistenceManagerFactory;
033: import java.util.*;
034: import java.sql.Connection;
035: import java.sql.SQLException;
036: import java.lang.reflect.Method;
037: import java.lang.reflect.Field;
038: import java.lang.reflect.InvocationTargetException;
039: import java.lang.reflect.Constructor;
040:
041: /**
042: * Base class for our PMF implementations.
043: */
044: public abstract class PersistenceManagerFactoryBase implements
045: VersantPMFInternal {
046:
047: protected Properties props;
048: protected LogEventStore pes;
049: protected ClassLoader loader;
050: protected StorageCache cache;
051: protected StorageManagerFactory smf;
052: protected StorageManagerFactory innermostSmf;
053: protected boolean jdbc;
054: protected ModelMetaData jmd;
055: protected MemQueryCompiler memQueryCompiler;
056: protected PMPool pmPool;
057: protected WeakBag activePMs = new WeakBag();
058: protected Object userObject;
059: protected ConfigInfo config;
060:
061: // the fields in the block below are used to configure PMs
062: protected boolean retainValues;
063: protected boolean restoreValues;
064: protected boolean optimistic;
065: protected boolean nontransactionalRead;
066: protected boolean nontransactionalWrite;
067: protected boolean ignoreCache;
068: protected boolean multithreaded;
069: protected boolean allowPmCloseWithOpenTx;
070: protected boolean interceptDfgFieldAccess;
071: protected boolean checkModelConsistencyOnCommit;
072: protected int pmCacheRefType;
073: protected int datastoreTxLocking;
074: protected int retainConnectionInOptTx;
075: protected LifecycleListenerManager listeners;
076:
077: protected int pmCreatedCount;
078: protected int pmClosedCount;
079: protected int pmClosedAutoCount;
080: protected int pmClosedAutoTxCount;
081:
082: private Field jdbcClassIdField;
083: private Method jdbcFindClassMethod;
084:
085: private Object entityManagerFactory;
086:
087: public PersistenceManagerFactoryBase(Properties props,
088: ClassLoader loader) {
089: boolean ok = false;
090: try {
091: this .props = props = (Properties) props.clone();
092:
093: config = new ConfigParser().parse(props);
094:
095: if (config.hyperdrive) {
096:
097: this .loader = new HyperdriveLoader(loader);
098:
099: } else {
100: this .loader = loader;
101: }
102:
103: pes = createLogEventStore();
104: cache = createStorageCache();
105: smf = createStorageManagerFactory();
106:
107: for (innermostSmf = smf;;) {
108: StorageManagerFactory next = innermostSmf
109: .getInnerStorageManagerFactory();
110: if (next == null)
111: break;
112: innermostSmf = next;
113: }
114: jdbc = innermostSmf.getClass().getName().indexOf(
115: "JdbcStorageManagerFactory") >= 0;
116:
117: jmd = smf.getModelMetaData();
118: jmd.checkForNonPCClasses();
119: jmd.forceClassRegistration();
120:
121: memQueryCompiler = new MemQueryCompiler(jmd, this .loader);
122:
123: retainValues = config.retainValues;
124: restoreValues = config.restoreValues;
125: optimistic = config.optimistic;
126: nontransactionalRead = config.nontransactionalRead;
127: nontransactionalWrite = config.nontransactionalWrite;
128: ignoreCache = config.ignoreCache;
129: multithreaded = config.multithreaded;
130: allowPmCloseWithOpenTx = config.allowPmCloseWithOpenTx;
131: interceptDfgFieldAccess = config.interceptDfgFieldAccess;
132: checkModelConsistencyOnCommit = config.checkModelConsistencyOnCommit;
133: pmCacheRefType = config.pmCacheRefType;
134: datastoreTxLocking = config.datastoreTxLocking;
135: retainConnectionInOptTx = config.retainConnectionInOptTx;
136:
137: if (config.pmpoolEnabled) {
138: pmPool = new PMPool(this , config.pmpoolMaxIdle, pes);
139: } else {
140: pmPool = null;
141: }
142: ok = true;
143: } finally {
144: if (!ok) {
145: try {
146: close();
147: } catch (Throwable e) {
148: // ignore - already busy with an exception
149: }
150: }
151: }
152: }
153:
154: /**
155: * Create our StorageManagerFactory.
156: */
157: protected abstract StorageManagerFactory createStorageManagerFactory();
158:
159: /**
160: * Create and configure our LogEventStore.
161: */
162: protected LogEventStore createLogEventStore() {
163: LogEventStore pes = new LogEventStore();
164: BeanUtils.setProperties(pes, config.perfProps);
165: return pes;
166: }
167:
168: /**
169: * Create our StorageCache implementation.
170: */
171: protected StorageCache createStorageCache() {
172: if (config.useCache) {
173: LRUStorageCache lruCache = new LRUStorageCache();
174: lruCache.setQueryCacheEnabled(config.queryCacheEnabled);
175: lruCache.setMaxQueries(config.maxQueriesToCache);
176: lruCache.setMaxObjects(config.cacheMaxObjects);
177: return lruCache;
178: } else {
179: return new NOPStorageCache();
180: }
181: }
182:
183: /**
184: * Get the properties that we were created from.
185: */
186: public Properties getInitProperties() {
187: return props;
188: }
189:
190: public synchronized void close() {
191: List list = getPersistenceManagers();
192: for (Iterator i = list.iterator(); i.hasNext();) {
193: PersistenceManager pm = (PersistenceManager) i.next();
194: if (!pm.isClosed()) {
195: try {
196: if (pm.currentTransaction().isActive()) {
197: pm.currentTransaction().rollback();
198: }
199: } catch (Exception e) {
200: // ignore
201: }
202: try {
203: pm.close();
204: } catch (Exception e) {
205: // ignore
206: }
207: }
208: }
209: if (cache != null) {
210: Object ctx = cache.beginTx();
211: cache.evictAll(ctx);
212: cache.endTx(ctx);
213: cache = null;
214: }
215: if (smf != null) {
216: smf.destroy();
217: smf = null;
218: }
219: jmd = null;
220: pmPool = null;
221: }
222:
223: public PersistenceManager getPersistenceManager() {
224: VersantPersistenceManagerImp pm;
225: if (pmPool != null) {
226: pm = pmPool.getPM();
227: } else {
228: pm = createVersantPersistenceManagerImp();
229: }
230: configurePM(pm);
231: synchronized (activePMs) {
232: activePMs.clean();
233: pm.setActiveReference(activePMs.add(pm));
234: }
235: return pm.getProxy();
236: }
237:
238: /**
239: * Restore a PM to default settings.
240: */
241: protected void configurePM(VersantPersistenceManagerImp pm) {
242: pm.setRetainValues(retainValues);
243: pm.setRestoreValues(restoreValues);
244: pm.setOptimistic(optimistic);
245: pm.setNontransactionalRead(nontransactionalRead);
246: pm.setNontransactionalWrite(nontransactionalWrite);
247: pm.setIgnoreCache(ignoreCache);
248: pm.setMultithreadedImp(multithreaded);
249: pm.setInterceptDfgFieldAccess(interceptDfgFieldAccess
250: || !optimistic);
251: pm
252: .setCheckModelConsistencyOnCommit(checkModelConsistencyOnCommit);
253: pm.getCache().setCurrentRefType(pmCacheRefType);
254: pm.setDatastoreTxLocking(datastoreTxLocking);
255: switch (retainConnectionInOptTx) {
256: case MDStatics.TRUE:
257: pm.setRetainConnectionInOptTx(true);
258: break;
259: case MDStatics.FALSE:
260: pm.setRetainConnectionInOptTx(false);
261: break;
262: }
263: pm.setListeners(listeners);
264: }
265:
266: /**
267: * Create a new, unconfigured, PM.
268: *
269: * @see #configurePM(VersantPersistenceManagerImp)
270: */
271: public synchronized VersantPersistenceManagerImp createVersantPersistenceManagerImp() {
272: VersantPersistenceManagerImp pm = null;
273: try {
274: pm = newVersantPersistenceManagerImp(smf
275: .getStorageManager());
276: if (pes.isFiner()) {
277: ServerLogEvent ev = new ServerLogEvent(
278: ServerLogEvent.PM_CREATED, null);
279: ev.zeroTotalMs();
280: pes.log(ev);
281: }
282: pmCreatedCount++;
283: return pm;
284: } catch (Exception e) {
285: throw handleException(e);
286: }
287: }
288:
289: protected VersantPersistenceManagerImp newVersantPersistenceManagerImp(
290: StorageManager sm) {
291: return new VersantPersistenceManagerImp(this , jmd, sm,
292: new LocalPMCache(101), memQueryCompiler);
293: }
294:
295: public void pmClosedNotification(VersantPersistenceManagerImp pm,
296: boolean fromFinalizer, boolean txWasActive) {
297: activePMs.remove(pm.getActiveReference());
298: pm.setActiveReference(null);
299: if (fromFinalizer) {
300: try {
301: pm.destroy();
302: } catch (Exception e) {
303: // ignore
304: }
305: if (txWasActive && pes.isWarning() || pes.isFine()) {
306: ServerLogEvent ev = new ServerLogEvent(
307: txWasActive ? ServerLogEvent.PM_CLOSED_AUTO_TX
308: : ServerLogEvent.PM_CLOSED_AUTO, null);
309: ev.zeroTotalMs();
310: pes.log(ev);
311: }
312: } else if (pmPool == null || pm.isMustNotPool()) {
313: pm.destroy();
314: if (pes.isFiner()) {
315: ServerLogEvent ev = new ServerLogEvent(
316: ServerLogEvent.PM_CLOSED, null);
317: ev.zeroTotalMs();
318: pes.log(ev);
319: }
320: } else {
321: pmPool.returnPM(pm);
322: }
323: }
324:
325: public PersistenceManager getPersistenceManager(String userid,
326: String password) {
327: return getPersistenceManager();
328: }
329:
330: public void setConnectionUserName(String userName) {
331: // ignore
332: }
333:
334: public String getConnectionUserName() {
335: return (String) props.get(ConfigParser.STD_CON_USER_NAME);
336: }
337:
338: public void setConnectionPassword(String password) {
339: // ignore
340: }
341:
342: public void setConnectionURL(String URL) {
343: // ignore
344: }
345:
346: public String getConnectionURL() {
347: return (String) props.get(ConfigParser.STD_CON_URL);
348: }
349:
350: public void setConnectionDriverName(String driverName) {
351: // ignore
352: }
353:
354: public String getConnectionDriverName() {
355: return (String) props.get(ConfigParser.STD_CON_DRIVER_NAME);
356: }
357:
358: public void setConnectionFactoryName(String connectionFactoryName) {
359: // ignore
360: }
361:
362: public String getConnectionFactoryName() {
363: return (String) props.get(ConfigParser.STD_CON_FACTORY_NAME);
364: }
365:
366: public void setConnectionFactory(Object connectionFactory) {
367: // ignore
368: }
369:
370: public Object getConnectionFactory() {
371: throw notImplemented();
372: }
373:
374: public void setConnectionFactory2Name(String connectionFactoryName) {
375: // ignore
376: }
377:
378: public String getConnectionFactory2Name() {
379: return (String) props.get(ConfigParser.STD_CON2_FACTORY_NAME);
380: }
381:
382: public void setConnectionFactory2(Object connectionFactory) {
383: // ignore
384: }
385:
386: public Object getConnectionFactory2() {
387: throw notImplemented();
388: }
389:
390: public void setMultithreaded(boolean flag) {
391: multithreaded = flag;
392: }
393:
394: public boolean getMultithreaded() {
395: return multithreaded;
396: }
397:
398: public void setOptimistic(boolean flag) {
399: optimistic = flag;
400: }
401:
402: public boolean getOptimistic() {
403: return optimistic;
404: }
405:
406: public void setRetainValues(boolean flag) {
407: retainValues = flag;
408: }
409:
410: public boolean getRetainValues() {
411: return retainValues;
412: }
413:
414: public void setRestoreValues(boolean restoreValues) {
415: this .restoreValues = restoreValues;
416: }
417:
418: public boolean getRestoreValues() {
419: return restoreValues;
420: }
421:
422: public void setNontransactionalRead(boolean flag) {
423: nontransactionalRead = flag;
424: }
425:
426: public boolean getNontransactionalRead() {
427: return nontransactionalRead;
428: }
429:
430: public void setNontransactionalWrite(boolean flag) {
431: nontransactionalWrite = flag;
432: }
433:
434: public boolean getNontransactionalWrite() {
435: return nontransactionalWrite;
436: }
437:
438: public void setIgnoreCache(boolean flag) {
439: ignoreCache = flag;
440: }
441:
442: public boolean getIgnoreCache() {
443: return ignoreCache;
444: }
445:
446: public Properties getProperties() {
447: Properties p = new Properties();
448: props.setProperty("VendorName", "Versant");
449: props.setProperty("VendorURL", "http://www.versant.com");
450: props.setProperty("VersionNumber", Debug.VERSION);
451: return p;
452: }
453:
454: public Collection supportedOptions() {
455: HashSet o = new HashSet();
456: o.add("javax.jdo.option.TransientTransactional");
457: o.add(ConfigParser.OPTION_NON_TRANSACTIONAL_READ);
458: o.add(ConfigParser.OPTION_NON_TRANSACTIONAL_WRITE);
459: o.add(ConfigParser.OPTION_RETAINVALUES);
460: o.add(ConfigParser.OPTION_RESTORE_VALUES);
461: o.add(ConfigParser.OPTION_OPTIMISTIC);
462: o.add(ConfigParser.OPTION_MULTITHREADED);
463: o.add("javax.jdo.option.ApplicationIdentity");
464: o.add("javax.jdo.option.DatastoreIdentity");
465: o.add("javax.jdo.option.ArrayList");
466: o.add("javax.jdo.option.HashMap");
467: o.add("javax.jdo.option.Hashtable");
468: o.add("javax.jdo.option.LinkedList");
469: o.add("javax.jdo.option.TreeMap");
470: o.add("javax.jdo.option.TreeSet");
471: o.add("javax.jdo.option.Vector");
472: o.add("javax.jdo.option.Map");
473: o.add("javax.jdo.option.List");
474: o.add("javax.jdo.option.Array");
475: o.add("javax.jdo.option.NullCollection");
476: o.add("javax.jdo.query.JDOQL");
477: smf.supportedOptions(o);
478: return o;
479: }
480:
481: public synchronized Connection getJdbcConnection(String datastore)
482: throws SQLException {
483: if (jdbc) {
484: return (Connection) innermostSmf.getDatastoreConnection();
485: } else {
486: throw BindingSupportImpl.getInstance().invalidOperation(
487: "Not supported by "
488: + innermostSmf.getClass().getName());
489: }
490: }
491:
492: public synchronized void clearConnectionPool(String datastore) {
493: smf.closeIdleDatastoreConnections();
494: }
495:
496: public void setUserObject(Object o) {
497: userObject = o;
498: }
499:
500: public Object getUserObject() {
501: return userObject;
502: }
503:
504: public boolean isInterceptDfgFieldAccess() {
505: return interceptDfgFieldAccess;
506: }
507:
508: public void setInterceptDfgFieldAccess(
509: boolean interceptDfgFieldAccess) {
510: this .interceptDfgFieldAccess = interceptDfgFieldAccess;
511: }
512:
513: public boolean isAllowPmCloseWithTxOpen() {
514: return allowPmCloseWithOpenTx;
515: }
516:
517: public void setAllowPmCloseWithTxOpen(boolean allowed) {
518: allowPmCloseWithOpenTx = allowed;
519: }
520:
521: public boolean isCheckModelConsistencyOnCommit() {
522: return checkModelConsistencyOnCommit;
523: }
524:
525: public void setCheckModelConsistencyOnCommit(boolean on) {
526: checkModelConsistencyOnCommit = on;
527: }
528:
529: public void setServerUserObject(Object o) {
530: setUserObject(o);
531: }
532:
533: public Object getServerUserObject() {
534: return getUserObject();
535: }
536:
537: public void shutdown() {
538: close();
539: }
540:
541: public LogEvent[] getNewPerfEvents(int lastId) {
542: return pes.copyEvents(lastId);
543: }
544:
545: public PmfStatus getPmfStatus() {
546: PmfStatus s = new PmfStatus();
547: s.setServer(getConnectionURL());
548: return s;
549: }
550:
551: public abstract Metric[] getMetrics();
552:
553: public abstract MetricSnapshotPacket getNewMetricSnapshots(
554: int lastId);
555:
556: public abstract MetricSnapshotPacket getMostRecentMetricSnapshot(
557: int lastId);
558:
559: public abstract void setUserMetric(String name, int value);
560:
561: public abstract void incUserMetric(String name, int delta);
562:
563: public abstract int getUserMetric(String name);
564:
565: public void logEvent(int level, String description, int ms) {
566: switch (level) {
567: case VersantPersistenceManagerFactory.EVENT_ERRORS:
568: if (!pes.isSevere())
569: return;
570: break;
571: case VersantPersistenceManagerFactory.EVENT_NORMAL:
572: if (!pes.isFine())
573: return;
574: break;
575: case VersantPersistenceManagerFactory.EVENT_VERBOSE:
576: if (!pes.isFiner())
577: return;
578: break;
579: case VersantPersistenceManagerFactory.EVENT_ALL:
580: if (!pes.isFinest())
581: return;
582: break;
583: }
584: ServerLogEvent ev = new ServerLogEvent(ServerLogEvent.USER,
585: description);
586: ev.setTotalMs(ms);
587: pes.log(ev);
588: }
589:
590: public void doSystemGC() {
591: System.gc();
592: }
593:
594: public PropertyInfo getServerConfiguration() {
595: return null;
596: }
597:
598: public String setServerProperty(String[] beanPath, String value) {
599: return null;
600: }
601:
602: public RemoteClientStatus[] getRemoteClients() {
603: return new RemoteClientStatus[0];
604: }
605:
606: public List getPersistenceManagers() {
607: List list;
608: synchronized (activePMs) {
609: list = activePMs.values();
610: }
611: ArrayList a = new ArrayList(list.size());
612: for (Iterator i = list.iterator(); i.hasNext();) {
613: VersantPersistenceManagerImp pm = (VersantPersistenceManagerImp) i
614: .next();
615: PMProxy proxy = pm.getProxy();
616: // proxy may be null if PM has been closed since we got list
617: if (proxy != null) {
618: a.add(proxy);
619: }
620: }
621: return a;
622: }
623:
624: public void evict(Object o) {
625: PmfEvictEvent ev = null;
626: if (pes.isFiner()) {
627: pes.log(ev = new PmfEvictEvent(o));
628: }
629: try {
630: OID oid = jmd.convertToOID(o);
631: Object ctx = cache.beginTx();
632: try {
633: cache.evict(ctx, new OID[] { oid }, 0, 1, 0);
634: } finally {
635: cache.endTx(ctx);
636: }
637: } catch (Throwable e) {
638: if (ev != null)
639: ev.setErrorMsg(e);
640: throw handleException(e);
641: } finally {
642: if (ev != null)
643: ev.updateTotalMs();
644: }
645: }
646:
647: public void evictAll(Object[] oids) {
648: PmfEvictEvent ev = null;
649: if (pes.isFiner()) {
650: pes.log(ev = new PmfEvictEvent(oids));
651: }
652: try {
653: OID[] a = jmd.convertToOID(oids, oids.length);
654: Object ctx = cache.beginTx();
655: try {
656: cache.evict(ctx, a, 0, a.length, 0);
657: } finally {
658: cache.endTx(ctx);
659: }
660: } catch (Throwable e) {
661: if (ev != null)
662: ev.setErrorMsg(e);
663: throw handleException(e);
664: } finally {
665: if (ev != null)
666: ev.updateTotalMs();
667: }
668: }
669:
670: public void evictAll(Collection oids) {
671: OID[] a = new OID[oids.size()];
672: int pos = 0;
673: for (Iterator i = oids.iterator(); i.hasNext();) {
674: a[pos++] = jmd.convertToOID(i.next());
675: }
676: PmfEvictEvent ev = null;
677: if (pes.isFiner()) {
678: pes.log(ev = new PmfEvictEvent(a));
679: }
680: try {
681: Object ctx = cache.beginTx();
682: try {
683: cache.evict(ctx, a, 0, a.length, 0);
684: } finally {
685: cache.endTx(ctx);
686: }
687: } catch (Throwable e) {
688: if (ev != null)
689: ev.setErrorMsg(e);
690: throw handleException(e);
691: } finally {
692: if (ev != null)
693: ev.updateTotalMs();
694: }
695: }
696:
697: public void evictAll(Class cls, boolean includeSubclasses) {
698: PmfEvictEvent ev = null;
699: if (pes.isFiner()) {
700: pes.log(ev = new PmfEvictEvent(cls, includeSubclasses));
701: }
702: try {
703: ClassMetaData cmd = jmd.getClassMetaData(cls);
704: if (cmd == null) {
705: throw BindingSupportImpl.getInstance()
706: .invalidOperation(
707: "Not a persistent class: "
708: + cls.getName());
709: }
710: ClassMetaData[] a;
711: if (includeSubclasses) {
712: a = jmd.getClassMetaDataForHeirachy(cmd);
713: } else {
714: a = new ClassMetaData[] { cmd };
715: }
716: Object ctx = cache.beginTx();
717: try {
718: cache.evict(ctx, a, a.length);
719: } finally {
720: cache.endTx(ctx);
721: }
722: } catch (Throwable e) {
723: if (ev != null)
724: ev.setErrorMsg(e);
725: throw handleException(e);
726: } finally {
727: if (ev != null)
728: ev.updateTotalMs();
729: }
730: }
731:
732: public void evictAll() {
733: PmfEvictEvent ev = null;
734: if (pes.isFine()) {
735: pes.log(ev = new PmfEvictEvent());
736: }
737: try {
738: Object ctx = cache.beginTx();
739: try {
740: cache.evictAll(ctx);
741: } finally {
742: cache.endTx(ctx);
743: }
744: } catch (Throwable e) {
745: if (ev != null)
746: ev.setErrorMsg(e);
747: throw handleException(e);
748: } finally {
749: if (ev != null)
750: ev.updateTotalMs();
751: }
752: }
753:
754: public boolean isInCache(Object oid) {
755: return cache.contains(jmd.convertToOID(oid));
756: }
757:
758: /**
759: * Get the meta data for cls or throw an exception if there is none.
760: */
761: protected ClassMetaData getClassMetaData(Class cls) {
762: ClassMetaData cmd = jmd.getClassMetaData(cls);
763: if (cmd == null) {
764: throw BindingSupportImpl.getInstance().invalidOperation(
765: "Class is not persistent: " + cls.getName());
766: }
767: return cmd;
768: }
769:
770: public int getClassID(Class cls) {
771: return getClassMetaData(cls).classId;
772: }
773:
774: public Class getClassForID(int classid) {
775: ClassMetaData cmd = jmd.getClassMetaData(classid);
776: if (cmd == null) {
777: throw BindingSupportImpl.getInstance().invalidOperation(
778: "No class found for classid: " + classid);
779: }
780: return cmd.cls;
781: }
782:
783: public Object getJdbcClassID(Class cls) {
784: if (jdbc) {
785: ClassMetaData cmd = getClassMetaData(cls);
786: try {
787: // this must be done with reflection to avoid engine depending
788: // on jdbc
789: if (jdbcClassIdField == null) {
790: jdbcClassIdField = cmd.storeClass.getClass()
791: .getField("jdbcClassId");
792: }
793: return jdbcClassIdField.get(cmd.storeClass);
794: } catch (Throwable e) {
795: throw handleException(e);
796: }
797: } else {
798: throw BindingSupportImpl.getInstance().invalidOperation(
799: "Class is not stored using JDBC: " + cls.getName());
800: }
801: }
802:
803: public Class getClassForJdbcID(Class baseClass, Object jdbcClassid) {
804: if (jdbc) {
805: ClassMetaData cmd = getClassMetaData(baseClass).top;
806: ClassMetaData ans;
807: try {
808: // this must be done with reflection to avoid engine depending
809: // on jdbc
810: if (jdbcFindClassMethod == null) {
811: jdbcFindClassMethod = cmd.storeClass.getClass()
812: .getMethod("findClass",
813: new Class[] { Object.class });
814: }
815: ans = (ClassMetaData) jdbcFindClassMethod.invoke(
816: cmd.storeClass, new Object[] { jdbcClassid });
817: } catch (Throwable e) {
818: throw handleException(e);
819: }
820: if (ans == null) {
821: throw BindingSupportImpl.getInstance()
822: .invalidOperation(
823: "No class found in hierarchy "
824: + cmd.qname
825: + " for jdbc-class-id: "
826: + jdbcClassid);
827: }
828: return ans.cls;
829: } else {
830: throw BindingSupportImpl.getInstance().invalidOperation(
831: "Class is not stored using JDBC: "
832: + baseClass.getName());
833: }
834: }
835:
836: public int getClassIndex(Class cls) {
837: return getClassMetaData(cls).index;
838: }
839:
840: public Class getClassForIndex(int index) {
841: try {
842: return jmd.classes[index].cls;
843: } catch (ArrayIndexOutOfBoundsException e) {
844: throw BindingSupportImpl.getInstance().invalidOperation(
845: "Invalid class index: " + index);
846: }
847: }
848:
849: public int[] getClassIndexes(Class[] classes,
850: boolean includeSubclasses) {
851: return jmd.convertToClassIndexes(classes, includeSubclasses);
852: }
853:
854: public void registerSCOPersistenceDelegates(Object encoder) {
855: try {
856: // this must be done with reflection so the code will compile
857: // and run on JDK 1.3 VMs
858: Class cls = Class
859: .forName("com.versant.core.jdo.sco.PersistenceDelegateManager");
860: Method method = cls
861: .getDeclaredMethod("register", new Class[] { Class
862: .forName("java.beans.Encoder") });
863: method.invoke(null, new Object[] { encoder });
864: } catch (Exception e) {
865: throw BindingSupportImpl.getInstance().invalidOperation(
866: "JDK 1.4 or newer VM required");
867: }
868: }
869:
870: public int getPmCacheRefType() {
871: return pmCacheRefType;
872: }
873:
874: public void setPmCacheRefType(int pmCacheRefType) {
875: this .pmCacheRefType = pmCacheRefType;
876: }
877:
878: public void closeActivePMsForTesting() {
879: }
880:
881: public DataStoreInfo getDataStoreInfo(String datastore) {
882: return smf.getDataStoreInfo();
883: }
884:
885: public void addLifecycleListener(LifecycleListener listener,
886: Class[] classes) {
887: if (classes != null) {
888: BindingSupportImpl
889: .getInstance()
890: .runtime(
891: "Support for non-null "
892: + "classes parameter has not been implemented");
893: }
894: if (listeners == null) {
895: listeners = new LifecycleListenerManager(listener);
896: } else {
897: listeners = listeners.add(listener);
898: }
899: }
900:
901: public void removeLifecycleListener(LifecycleListener listener) {
902: if (listeners == null) {
903: return;
904: }
905: listeners = listeners.remove(listener);
906: }
907:
908: /**
909: * Wrap an exception appropriately and return one to be thrown.
910: */
911: protected RuntimeException handleException(Throwable e) {
912: return handleException(e.toString(), e);
913: }
914:
915: /**
916: * Wrap an exception appropriately and return one to be thrown.
917: */
918: protected RuntimeException handleException(String msg, Throwable e) {
919: if (e instanceof InvocationTargetException) {
920: e = ((InvocationTargetException) e).getTargetException();
921: }
922: if (BindingSupportImpl.getInstance().isError(e)
923: && !BindingSupportImpl.getInstance()
924: .isOutOfMemoryError(e)) {
925: throw (Error) e;
926: }
927: if (BindingSupportImpl.getInstance().isOwnException(e)) {
928: return (RuntimeException) e;
929: }
930: return BindingSupportImpl.getInstance().internal(msg, e);
931: }
932:
933: /**
934: * Return a 'not implemented' exception.
935: */
936: protected RuntimeException notImplemented() {
937: return BindingSupportImpl.getInstance().notImplemented("");
938: }
939:
940: public StorageCache getStorageCache() {
941: return cache;
942: }
943:
944: public StorageManagerFactory getStorageManagerFactory() {
945: return smf;
946: }
947:
948: public ModelMetaData getJDOMetaData() {
949: return jmd;
950: }
951:
952: public LogEventStore getLogEventStore() {
953: return pes;
954: }
955:
956: public ClassLoader getClassLoader() {
957: return loader;
958: }
959:
960: public abstract boolean isLocal();
961:
962: public synchronized Object getEntityManagerFactory() {
963: if (entityManagerFactory != null)
964: return entityManagerFactory;
965:
966: try {
967: Class emf = loader
968: .loadClass("com.versant.core.ejb.EntityManagerFactoryImp");
969: Constructor cons = emf
970: .getConstructor(new Class[] { PersistenceManagerFactory.class });
971: entityManagerFactory = cons
972: .newInstance(new Object[] { this });
973: } catch (Throwable e) {
974: //ignore all
975: e.printStackTrace(System.out);
976: }
977: return entityManagerFactory;
978: }
979:
980: /**
981: * Classloader that will load hyperdrive classes before delegating to
982: * the parent classloader.
983: */
984:
985: public static class HyperdriveLoader extends ClassLoader {
986:
987: public HyperdriveLoader(ClassLoader parent) {
988: super(parent);
989: }
990:
991: }
992:
993: }
|