001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.objectserver.managedobject;
006:
007: import EDU.oswego.cs.dl.util.concurrent.ConcurrentHashMap;
008:
009: import com.tc.exception.TCRuntimeException;
010: import com.tc.io.serializer.api.StringIndex;
011: import com.tc.object.LiteralValues;
012: import com.tc.object.ObjectID;
013: import com.tc.object.dna.api.DNACursor;
014: import com.tc.object.loaders.Namespace;
015: import com.tc.objectserver.core.api.ManagedObjectState;
016: import com.tc.objectserver.persistence.api.PersistentCollectionFactory;
017: import com.tc.objectserver.persistence.api.Persistor;
018: import com.tc.util.Assert;
019:
020: import java.io.IOException;
021: import java.io.ObjectInput;
022: import java.util.Map;
023:
024: /**
025: * Creates state for managed objects
026: */
027: public class ManagedObjectStateFactory {
028:
029: private static final LiteralValues literalValues = (LiteralValues) new LiteralValues();
030: private static final Map classNameToStateMap = new ConcurrentHashMap();
031: private final ManagedObjectChangeListenerProvider listenerProvider;
032: private final StringIndex stringIndex;
033: private final PhysicalManagedObjectStateFactory physicalMOFactory;
034:
035: /**
036: * I know singletons are BAD, but this way we save about 16 bytes for every shared object we store in the server and
037: * that is huge ! So I can compromise here.
038: */
039: private static volatile ManagedObjectStateFactory singleton;
040:
041: // this is present for tests
042: private static boolean disableAssertions = false;
043:
044: private final PersistentCollectionFactory persistentCollectionFactory;
045:
046: static {
047: classNameToStateMap.put(java.util.IdentityHashMap.class
048: .getName(), new Byte(ManagedObjectState.MAP_TYPE));
049: classNameToStateMap.put(java.util.Hashtable.class.getName(),
050: new Byte(ManagedObjectState.PARTIAL_MAP_TYPE));
051: classNameToStateMap.put(java.util.Properties.class.getName(),
052: new Byte(ManagedObjectState.PARTIAL_MAP_TYPE));
053: classNameToStateMap.put(gnu.trove.THashMap.class.getName(),
054: new Byte(ManagedObjectState.MAP_TYPE));
055: classNameToStateMap.put(java.util.HashMap.class.getName(),
056: new Byte(ManagedObjectState.PARTIAL_MAP_TYPE));
057: classNameToStateMap.put(java.util.Collections.EMPTY_MAP
058: .getClass().getName(), new Byte(
059: ManagedObjectState.MAP_TYPE));
060: classNameToStateMap.put(
061: java.util.LinkedHashMap.class.getName(), new Byte(
062: ManagedObjectState.LINKED_HASHMAP_TYPE));
063: classNameToStateMap.put(java.util.TreeMap.class.getName(),
064: new Byte(ManagedObjectState.TREE_MAP_TYPE));
065: classNameToStateMap.put(gnu.trove.THashSet.class.getName(),
066: new Byte(ManagedObjectState.SET_TYPE));
067: classNameToStateMap.put(java.util.HashSet.class.getName(),
068: new Byte(ManagedObjectState.SET_TYPE));
069: classNameToStateMap.put(
070: java.util.LinkedHashSet.class.getName(), new Byte(
071: ManagedObjectState.SET_TYPE));
072: classNameToStateMap.put(java.util.Collections.EMPTY_SET
073: .getClass().getName(), new Byte(
074: ManagedObjectState.SET_TYPE));
075: classNameToStateMap.put(java.util.TreeSet.class.getName(),
076: new Byte(ManagedObjectState.TREE_SET_TYPE));
077: classNameToStateMap.put(java.util.LinkedList.class.getName(),
078: new Byte(ManagedObjectState.LIST_TYPE));
079: classNameToStateMap.put(java.util.ArrayList.class.getName(),
080: new Byte(ManagedObjectState.LIST_TYPE));
081: classNameToStateMap.put(java.util.Vector.class.getName(),
082: new Byte(ManagedObjectState.LIST_TYPE));
083: classNameToStateMap.put(java.util.Stack.class.getName(),
084: new Byte(ManagedObjectState.LIST_TYPE));
085: classNameToStateMap.put(java.util.Collections.EMPTY_LIST
086: .getClass().getName(), new Byte(
087: ManagedObjectState.LIST_TYPE));
088: classNameToStateMap.put(java.util.Date.class.getName(),
089: new Byte(ManagedObjectState.DATE_TYPE));
090: classNameToStateMap.put(java.sql.Date.class.getName(),
091: new Byte(ManagedObjectState.DATE_TYPE));
092: classNameToStateMap.put(java.sql.Time.class.getName(),
093: new Byte(ManagedObjectState.DATE_TYPE));
094: classNameToStateMap.put(java.sql.Timestamp.class.getName(),
095: new Byte(ManagedObjectState.DATE_TYPE));
096: classNameToStateMap.put(java.net.URL.class.getName(), new Byte(
097: ManagedObjectState.URL_TYPE));
098: // These 1.5 classes needs to be compiled in 1.4 !!
099: classNameToStateMap.put(
100: "java.util.concurrent.LinkedBlockingQueue", new Byte(
101: ManagedObjectState.QUEUE_TYPE));
102: classNameToStateMap.put(
103: "java.util.concurrent.ConcurrentHashMap", new Byte(
104: ManagedObjectState.CONCURRENT_HASHMAP_TYPE));
105: }
106:
107: private ManagedObjectStateFactory(
108: ManagedObjectChangeListenerProvider listenerProvider,
109: StringIndex stringIndex,
110: PhysicalManagedObjectStateFactory physicalMOFactory,
111: PersistentCollectionFactory factory) {
112: this .listenerProvider = listenerProvider;
113: this .stringIndex = stringIndex;
114: this .physicalMOFactory = physicalMOFactory;
115: this .persistentCollectionFactory = factory;
116: }
117:
118: /*
119: * @see comments above
120: */
121: public static synchronized ManagedObjectStateFactory createInstance(
122: ManagedObjectChangeListenerProvider listenerProvider,
123: Persistor persistor) {
124: if (singleton != null && !disableAssertions) {
125: // not good !!
126: throw new AssertionError(
127: "This class is singleton. It is not to be instanciated more than once. "
128: + singleton);
129: }
130: singleton = new ManagedObjectStateFactory(listenerProvider,
131: persistor.getStringIndex(),
132: new PhysicalManagedObjectStateFactory(persistor
133: .getClassPersistor()), persistor
134: .getPersistentCollectionFactory());
135: return singleton;
136: }
137:
138: // This is provided only for testing
139: public static synchronized void disableSingleton(boolean b) {
140: disableAssertions = b;
141: }
142:
143: // This is provided only for testing
144: public static synchronized void setInstance(
145: ManagedObjectStateFactory factory) {
146: Assert.assertNotNull(factory);
147: singleton = factory;
148: }
149:
150: /**
151: * This method is not synchronized as the creation and access happens sequencially and this is a costly method to
152: * synchronize and singleton is a volatile variable
153: */
154: public static ManagedObjectStateFactory getInstance() {
155: Assert.assertNotNull(singleton);
156: return singleton;
157: }
158:
159: public StringIndex getStringIndex() {
160: return stringIndex;
161: }
162:
163: public ManagedObjectChangeListener getListener() {
164: return listenerProvider.getListener();
165: }
166:
167: public ManagedObjectState createState(ObjectID oid,
168: ObjectID parentID, String className, String loaderDesc,
169: DNACursor cursor) {
170: byte type = getStateObjectTypeFor(className);
171:
172: if (type == ManagedObjectState.LITERAL_TYPE) {
173: return new LiteralTypesManagedObjectState();
174: }
175:
176: final long classID = getClassID(className, loaderDesc);
177:
178: if (type == ManagedObjectState.PHYSICAL_TYPE) {
179: return physicalMOFactory.create(classID, parentID,
180: className, loaderDesc, cursor);
181: }
182: switch (type) {
183: case ManagedObjectState.ARRAY_TYPE:
184: return new ArrayManagedObjectState(classID);
185: case ManagedObjectState.MAP_TYPE:
186: return new MapManagedObjectState(classID,
187: persistentCollectionFactory
188: .createPersistentMap(oid));
189: case ManagedObjectState.PARTIAL_MAP_TYPE:
190: return new PartialMapManagedObjectState(classID,
191: persistentCollectionFactory
192: .createPersistentMap(oid));
193: case ManagedObjectState.LINKED_HASHMAP_TYPE:
194: return new LinkedHashMapManagedObjectState(classID);
195: case ManagedObjectState.TREE_MAP_TYPE:
196: return new TreeMapManagedObjectState(classID);
197: case ManagedObjectState.SET_TYPE:
198: return new SetManagedObjectState(classID);
199: case ManagedObjectState.TREE_SET_TYPE:
200: return new TreeSetManagedObjectState(classID);
201: case ManagedObjectState.LIST_TYPE:
202: return new ListManagedObjectState(classID);
203: case ManagedObjectState.QUEUE_TYPE:
204: return new QueueManagedObjectState(classID);
205: case ManagedObjectState.DATE_TYPE:
206: return new DateManagedObjectState(classID);
207: case ManagedObjectState.CONCURRENT_HASHMAP_TYPE:
208: return new ConcurrentHashMapManagedObjectState(classID);
209: case ManagedObjectState.URL_TYPE:
210: return new URLManagedObjectState(classID);
211: }
212: // Unreachable
213: throw new AssertionError("Type : " + type + " is unknown !");
214: }
215:
216: private long getClassID(String className, String loaderDesc) {
217: return getStringIndex().getOrCreateIndexFor(
218: loaderDesc + Namespace.getClassNameAndLoaderSeparator()
219: + className);
220: }
221:
222: public String getClassName(long classID) {
223: String s = null;
224: try {
225: String separator = Namespace
226: .getClassNameAndLoaderSeparator();
227: s = getStringIndex().getStringFor(classID);
228: return s.substring(s.indexOf(separator)
229: + separator.length());
230: } catch (Exception ex) {
231: throw new AssertionError(
232: "loaderDesc://:ClassName string for classId "
233: + classID + " not in the right format : "
234: + s);
235: }
236: }
237:
238: public String getLoaderDescription(long classID) {
239: String s = null;
240: try {
241: String separator = Namespace
242: .getClassNameAndLoaderSeparator();
243: s = getStringIndex().getStringFor(classID);
244: return s.substring(0, s.indexOf(separator));
245: } catch (Exception ex) {
246: throw new AssertionError(
247: "loaderDesc://:ClassName string for classId "
248: + classID + " not in the right format : "
249: + s);
250: }
251: }
252:
253: private byte getStateObjectTypeFor(String className) {
254: String logicalExtendingClassName = Namespace
255: .parseLogicalNameIfNeceesary(className);
256: if (logicalExtendingClassName != null) {
257: Byte t = (Byte) classNameToStateMap
258: .get(logicalExtendingClassName);
259: if (t != null) {
260: return t.byteValue();
261: }
262:
263: className = Namespace.parseClassNameIfNecessary(className);
264: }
265:
266: if (className.startsWith("[")) {
267: return ManagedObjectState.ARRAY_TYPE;
268: }
269: Byte type = (Byte) classNameToStateMap.get(className);
270: if (type != null) {
271: return type.byteValue();
272: }
273: if (literalValues.isLiteral(className)) {
274: return ManagedObjectState.LITERAL_TYPE;
275: }
276: return ManagedObjectState.PHYSICAL_TYPE;
277: }
278:
279: public PhysicalManagedObjectState createPhysicalState(
280: ObjectID parentID, int classId)
281: throws ClassNotFoundException {
282: return physicalMOFactory.create(parentID, classId);
283: }
284:
285: public ManagedObjectState readManagedObjectStateFrom(
286: ObjectInput in, byte type) {
287: try {
288: switch (type) {
289: case ManagedObjectState.PHYSICAL_TYPE:
290: return PhysicalManagedObjectState.readFrom(in);
291: case ManagedObjectState.MAP_TYPE:
292: return MapManagedObjectState.readFrom(in);
293: case ManagedObjectState.PARTIAL_MAP_TYPE:
294: return PartialMapManagedObjectState.readFrom(in);
295: case ManagedObjectState.LINKED_HASHMAP_TYPE:
296: return LinkedHashMapManagedObjectState.readFrom(in);
297: case ManagedObjectState.ARRAY_TYPE:
298: return ArrayManagedObjectState.readFrom(in);
299: case ManagedObjectState.DATE_TYPE:
300: return DateManagedObjectState.readFrom(in);
301: case ManagedObjectState.LITERAL_TYPE:
302: return LiteralTypesManagedObjectState.readFrom(in);
303: case ManagedObjectState.LIST_TYPE:
304: return ListManagedObjectState.readFrom(in);
305: case ManagedObjectState.SET_TYPE:
306: return SetManagedObjectState.readFrom(in);
307: case ManagedObjectState.TREE_SET_TYPE:
308: return TreeSetManagedObjectState.readFrom(in);
309: case ManagedObjectState.TREE_MAP_TYPE:
310: return TreeMapManagedObjectState.readFrom(in);
311: case ManagedObjectState.CONCURRENT_HASHMAP_TYPE:
312: return ConcurrentHashMapManagedObjectState.readFrom(in);
313: case ManagedObjectState.QUEUE_TYPE:
314: return QueueManagedObjectState.readFrom(in);
315: case ManagedObjectState.URL_TYPE:
316: return URLManagedObjectState.readFrom(in);
317: default:
318: throw new AssertionError("Unknown type : " + type
319: + " : Dont know how to deserialize this type !");
320: }
321: } catch (IOException e) {
322: throw new TCRuntimeException(e);
323: } catch (ClassNotFoundException e) {
324: throw new TCRuntimeException(e);
325: }
326: }
327:
328: public ManagedObjectState recreateState(ObjectID id, ObjectID pid,
329: String className, String loaderDesc, DNACursor cursor,
330: ManagedObjectState oldState) {
331: Assert.assertEquals(ManagedObjectState.PHYSICAL_TYPE, oldState
332: .getType());
333: final long classID = getClassID(className, loaderDesc);
334: return physicalMOFactory.recreate(classID, pid, className,
335: loaderDesc, cursor,
336: (PhysicalManagedObjectState) oldState);
337: }
338: }
|