001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package com.db4o.reflect.generic;
022:
023: import com.db4o.foundation.*;
024: import com.db4o.internal.*;
025: import com.db4o.internal.marshall.*;
026: import com.db4o.reflect.*;
027:
028: /**
029: * @exclude
030: */
031: public class KnownClassesRepository {
032:
033: // FIXME very java-centric, what about .NET?
034: private final static Hashtable4 PRIMITIVES;
035:
036: static {
037: PRIMITIVES = new Hashtable4();
038: registerPrimitive(Boolean.class, boolean.class);
039: registerPrimitive(Byte.class, byte.class);
040: registerPrimitive(Short.class, short.class);
041: registerPrimitive(Character.class, char.class);
042: registerPrimitive(Integer.class, int.class);
043: registerPrimitive(Long.class, long.class);
044: registerPrimitive(Float.class, float.class);
045: registerPrimitive(Double.class, double.class);
046: }
047:
048: private static void registerPrimitive(Class wrapper, Class primitive) {
049: PRIMITIVES.put(wrapper.getName(), primitive);
050: }
051:
052: private ObjectContainerBase _stream;
053: private Transaction _trans;
054:
055: private ReflectClassBuilder _builder;
056:
057: private final Hashtable4 _classByName = new Hashtable4();
058: private final Hashtable4 _classByID = new Hashtable4();
059: private Collection4 _pendingClasses = new Collection4();
060: private final Collection4 _classes = new Collection4();
061:
062: public KnownClassesRepository(ReflectClassBuilder builder) {
063: _builder = builder;
064: }
065:
066: public void setTransaction(Transaction trans) {
067: if (trans != null) {
068: _trans = trans;
069: _stream = trans.container();
070: }
071: }
072:
073: public void register(ReflectClass clazz) {
074: _classByName.put(clazz.getName(), clazz);
075: _classes.add(clazz);
076: }
077:
078: public ReflectClass forID(int id) {
079: if (_stream.handlers().isSystemHandler(id)) {
080: return _stream.handlers().classForID(id);
081: }
082: ensureClassAvailability(id);
083: return lookupByID(id);
084: }
085:
086: public ReflectClass forName(String className) {
087: final ReflectClass clazz = (ReflectClass) _classByName
088: .get(className);
089: if (clazz != null) {
090: return clazz;
091: }
092:
093: if (_stream == null) {
094: return null;
095: }
096:
097: if (_stream.classCollection() == null) {
098: return null;
099: }
100:
101: int classID = _stream.classMetadataIdForName(className);
102: if (classID <= 0) {
103: return null;
104: }
105:
106: return initializeClass(classID, className);
107: }
108:
109: private ReflectClass initializeClass(int classID, String className) {
110: ReflectClass newClazz = ensureClassInitialised(classID);
111: _classByName.put(className, newClazz);
112: return newClazz;
113: }
114:
115: private void readAll() {
116: for (Iterator4 idIter = _stream.classCollection().ids(); idIter
117: .moveNext();) {
118: ensureClassAvailability(((Integer) idIter.current())
119: .intValue());
120: }
121: for (Iterator4 idIter = _stream.classCollection().ids(); idIter
122: .moveNext();) {
123: ensureClassRead(((Integer) idIter.current()).intValue());
124: }
125: }
126:
127: private ReflectClass ensureClassAvailability(int id) {
128:
129: if (id == 0) {
130: return null;
131: }
132:
133: ReflectClass ret = (ReflectClass) _classByID.get(id);
134: if (ret != null) {
135: return ret;
136: }
137:
138: Buffer classreader = _stream.readWriterByID(_trans, id);
139:
140: ClassMarshaller marshaller = marshallerFamily()._class;
141: RawClassSpec spec = marshaller.readSpec(_trans, classreader);
142:
143: String className = spec.name();
144: ret = (ReflectClass) _classByName.get(className);
145: if (ret != null) {
146: _classByID.put(id, ret);
147: _pendingClasses.add(new Integer(id));
148: return ret;
149: }
150:
151: ret = _builder.createClass(className,
152: ensureClassAvailability(spec.super ClassID()), spec
153: .numFields());
154:
155: // step 1 only add to _classByID, keep the class out of _classByName and _classes
156: _classByID.put(id, ret);
157: _pendingClasses.add(new Integer(id));
158:
159: return ret;
160: }
161:
162: private void ensureClassRead(int id) {
163:
164: ReflectClass clazz = lookupByID(id);
165:
166: Buffer classreader = _stream.readWriterByID(_trans, id);
167:
168: ClassMarshaller classMarshaller = marshallerFamily()._class;
169: RawClassSpec classInfo = classMarshaller.readSpec(_trans,
170: classreader);
171: String className = classInfo.name();
172:
173: // Having the class in the _classByName Map for now indicates
174: // that the class is fully read. This is breakable if we start
175: // returning GenericClass'es in other methods like forName
176: // even if a native class has not been found
177: if (_classByName.get(className) != null) {
178: return;
179: }
180:
181: // step 2 add the class to _classByName and _classes to denote reading is completed
182: _classByName.put(className, clazz);
183: _classes.add(clazz);
184:
185: int numFields = classInfo.numFields();
186: ReflectField[] fields = _builder.fieldArray(numFields);
187: FieldMarshaller fieldMarshaller = marshallerFamily()._field;
188:
189: for (int i = 0; i < numFields; i++) {
190:
191: RawFieldSpec fieldInfo = fieldMarshaller.readSpec(_stream,
192: classreader);
193: String fieldName = fieldInfo.name();
194: ReflectClass fieldClass = reflectClassForFieldSpec(fieldInfo);
195: fields[i] = _builder.createField(clazz, fieldName,
196: fieldClass, fieldInfo.isVirtual(), fieldInfo
197: .isPrimitive(), fieldInfo.isArray(),
198: fieldInfo.isNArray());
199: }
200: _builder.initFields(clazz, fields);
201: }
202:
203: private ReflectClass reflectClassForFieldSpec(RawFieldSpec fieldInfo) {
204:
205: if (fieldInfo.isVirtual()) {
206: return virtualFieldByName(fieldInfo.name())
207: .classReflector();
208: }
209:
210: final int handlerID = fieldInfo.handlerID();
211:
212: // need to take care of special handlers here
213: switch (handlerID) {
214: case Handlers4.UNTYPED_ID:
215: return objectClass();
216: case Handlers4.ANY_ARRAY_ID:
217: return arrayClass(objectClass());
218: default:
219: ReflectClass fieldClass = forID(handlerID);
220: if (null != fieldClass) {
221: return normalizeFieldClass(fieldInfo, fieldClass);
222: }
223: break;
224: }
225: return null;
226: }
227:
228: private ReflectClass normalizeFieldClass(RawFieldSpec fieldInfo,
229: ReflectClass fieldClass) {
230: // TODO: why the following line is necessary?
231: ReflectClass theClass = _stream.reflector().forName(
232: fieldClass.getName());
233: if (fieldInfo.isPrimitive()) {
234: theClass = primitiveClass(theClass);
235: }
236: if (fieldInfo.isArray()) {
237: theClass = arrayClass(theClass);
238: }
239: return theClass;
240: }
241:
242: private ReflectClass objectClass() {
243: return _stream.reflector().forClass(Object.class);
244: }
245:
246: private VirtualFieldMetadata virtualFieldByName(
247: final String fieldName) {
248: return _stream.handlers().virtualFieldByName(fieldName);
249: }
250:
251: private MarshallerFamily marshallerFamily() {
252: return MarshallerFamily.forConverterVersion(_stream
253: .converterVersion());
254: }
255:
256: private ReflectClass ensureClassInitialised(int id) {
257: ReflectClass ret = ensureClassAvailability(id);
258: while (_pendingClasses.size() > 0) {
259: Collection4 pending = _pendingClasses;
260: _pendingClasses = new Collection4();
261: Iterator4 i = pending.iterator();
262: while (i.moveNext()) {
263: ensureClassRead(((Integer) i.current()).intValue());
264: }
265: }
266: return ret;
267: }
268:
269: public Iterator4 classes() {
270: readAll();
271: return _classes.iterator();
272: }
273:
274: public void register(int id, ReflectClass clazz) {
275: _classByID.put(id, clazz);
276: }
277:
278: public ReflectClass lookupByID(int id) {
279: return (ReflectClass) _classByID.get(id);
280: }
281:
282: public ReflectClass lookupByName(String name) {
283: return (ReflectClass) _classByName.get(name);
284: }
285:
286: private ReflectClass arrayClass(ReflectClass clazz) {
287: Object proto = clazz.reflector().array().newInstance(clazz, 0);
288: return clazz.reflector().forObject(proto);
289: }
290:
291: private ReflectClass primitiveClass(ReflectClass baseClass) {
292: Class primitive = (Class) PRIMITIVES.get(baseClass.getName());
293: if (primitive != null) {
294: return baseClass.reflector().forClass(primitive);
295: }
296: return baseClass;
297: }
298: }
|