001: // You can redistribute this software and/or modify it under the terms of
002: // the Ozone Core License version 1 published by ozone-db.org.
003: //
004: // The original code and portions created by SMB are
005: // Copyright (C) 1997-@year@ by SMB GmbH. All rights reserved.
006: //
007: // $Id: ClassicObjectContainer.java,v 1.1 2001/12/18 10:31:30 per_nyfelt Exp $
008:
009: package org.ozoneDB.core.classicStore;
010:
011: import java.io.*;
012: import java.util.*;
013: import java.lang.reflect.*;
014: import org.ozoneDB.*;
015: import org.ozoneDB.tools.*;
016: import org.ozoneDB.DxLib.*;
017: import org.ozoneDB.core.*;
018: import org.ozoneDB.util.*;
019:
020: /**
021: */
022: public final class ClassicObjectContainer extends DxObject implements
023: ObjectContainer, Externalizable {
024:
025: /** magic number for streaming */
026: protected final static long serialVersionUID = 2;
027: protected final static byte subSerialVersionUID = 1;
028:
029: /** global method cache */
030: private static DxHashMap methodTable = new DxHashMap(64);
031:
032: /** objekte werden nach transaktion nicht geloescht */
033: protected static boolean keepObjectsAlive = true;
034:
035: /** The environment of this object. */
036: protected transient Env env;
037: protected transient ClusterSpace clusterSpace;
038:
039: /** permissions */
040: protected Permissions permissions;
041:
042: /** null, if not activted */
043: protected OzoneCompatible target;
044: /** */
045: protected OzoneCompatible targetShadow;
046: /** */
047: protected byte[] targetBackup;
048:
049: /** time of last invoke */
050: protected long touchTime = System.currentTimeMillis();
051: protected short touchCount = 1;
052: protected boolean touched = false;
053:
054: /** a possible name for the object */
055: protected String name;
056:
057: /** the id of the object */
058: protected ObjectID objID;
059: /** the cluster id where the object is stored */
060: protected ClusterID clusterID;
061:
062: /** the lock of the object */
063: protected Lock lock = null;
064:
065: /** */
066: protected boolean deleted = false;
067: /** */
068: protected boolean created = false;
069:
070: /**
071: * constructor fuer streaming
072: */
073: public ClassicObjectContainer() {
074: created = false;
075: deleted = false;
076: }
077:
078: /**
079: * constructor; name ist optional
080: */
081: public ClassicObjectContainer(OzoneCompatible _target,
082: ObjectID _objID, Permissions _permissions) {
083: env = Env.currentEnv();
084: clusterSpace = ((ClassicStore) env.store).objectSpace.clusterSpace;
085:
086: target = _target;
087: objID = _objID;
088: permissions = _permissions;
089: lock = new DefaultLock();
090: created = true;
091: deleted = false;
092:
093: target.setContainer(this );
094: }
095:
096: // #### methods from ObjectContainer ######################################
097:
098: /**
099: * True, wenn beide auf ein OzoneCompatible mit gleicher ID verweisen.
100: */
101: public boolean equals(Object obj) {
102: if (obj instanceof ClassicObjectContainer) {
103: ClassicObjectContainer rhs = (ClassicObjectContainer) obj;
104: if (objID.equals(rhs.objID)) {
105: return true;
106: }
107: }
108:
109: return false;
110: }
111:
112: /** */
113: public void finalizeTarget() throws Exception {
114: activatedObject().done();
115: }
116:
117: /** */
118: public ObjectID id() {
119: return objID;
120: }
121:
122: /** */
123: public boolean isCreated() {
124: return created;
125: }
126:
127: /** */
128: public void deleteTarget() {
129: deleted = true;
130: }
131:
132: /** */
133: public boolean isDeleted() {
134: return deleted;
135: }
136:
137: /** */
138: public Object invokeTarget(Env env, String methodName, String sig,
139: Object[] args) throws Exception {
140: clusterSpace.touchObject(objID);
141:
142: Method method = methodFor(methodName, sig, args);
143: if (method == null) {
144: throw new MethodNotFoundExc(methodName);
145: }
146:
147: return method.invoke(activatedObject(), args);
148: }
149:
150: /** */
151: public void touch() {
152: touched = true;
153: ++touchCount;
154: touchTime = System.currentTimeMillis();
155: }
156:
157: /** */
158: public String name() {
159: return name;
160: }
161:
162: /** */
163: public void setName(String _name) {
164: nameTarget(_name);
165: }
166:
167: /** */
168: public void nameTarget(String _name) {
169: name = _name;
170: }
171:
172: /** */
173: public Permissions permissions() {
174: return permissions;
175: }
176:
177: /**
178: * Build a copy of the encap object. This is based on serialization,
179: * so no clone() method must be implemented by OzoneObjects.
180: */
181: public OzoneCompatible targetClone() throws Exception {
182: ByteArrayOutputStream bout = new ByteArrayOutputStream();
183: ObjectOutputStream out = new ObjectOutputStream(bout);
184: out.writeObject(activatedObject());
185: out.close();
186: ObjectInputStream in = new ObjectInputStream(
187: new ByteArrayInputStream(bout.toByteArray()));
188: OzoneCompatible result = (OzoneCompatible) in.readObject();
189: in.close();
190:
191: return result;
192: }
193:
194: /**
195: */
196: public OzoneProxy ozoneProxy() {
197: try {
198: String name = objectClass().getName() + PROXYNAME_POSTFIX;
199: OzoneProxy rObj = (OzoneProxy) env.classManager
200: .classForName(name).newInstance();
201: rObj.remoteID = id();
202: rObj.link = env.database;
203: return rObj;
204: } catch (Exception e) {
205: env.logWriter
206: .newEntry(
207: this ,
208: "ozoneProxy(): unable to create proper proxy object.",
209: e, LogWriter.WARN);
210: return new OzoneProxy(id());
211: }
212: }
213:
214: /** */
215: public int lockLevel(Transaction ta) {
216: return lock.level(ta);
217: }
218:
219: /**
220: * Gibt collection mit entweder dem writeLocker oder allen
221: * readLockern, d.h. alle potentiell behindernden transaktionen
222: */
223: public DxCollection allLockers() {
224: DxCollection lockerIDs = lock.lockerIDs();
225:
226: DxArrayBag result = new DxArrayBag(lockerIDs.count());
227: DxIterator it = lockerIDs.iterator();
228: while (it.next() != null) {
229: result.add(env.transactionManager
230: .taForID((TransactionID) it.object()));
231: }
232:
233: return result;
234: }
235:
236: /** */
237: public synchronized void notifyAllTAs(Transaction ta) {
238: env.logWriter.newEntry(this , ta.toString()
239: + " notify all TAs...", LogWriter.DEBUG3);
240: lock.notifyAll();
241: }
242:
243: // #### methods from ClassicObjectContainer ###############################
244:
245: /**
246: */
247: public OzoneCompatible targetShadow() {
248: return targetShadow;
249: }
250:
251: /**
252: * Liefert referenz auf das eigentliche objekt. darf nicht
253: * targetShadow beruecksichtigen, da ClusterSPace darauf aufbaut.
254: */
255: public OzoneCompatible target() {
256: return target;
257: }
258:
259: /**
260: * Setzen oder loeschen des objektes. commit() ist unteilbar, deshalb
261: * kein snchronized.
262: * Achtung: object ist evtl. gerade geclustert und muss vorher
263: * eingelagert werden; das darf nicht hier gemacht werden, da
264: * diese methode auch vom store benutzt wird.
265: */
266: protected OzoneCompatible setObject(OzoneCompatible obj) {
267: OzoneCompatible old = target;
268: target = obj;
269: if (target != null) {
270: target.setContainer(this );
271: if (targetShadow != null) {
272: env.logWriter.newEntry(this ,
273: "setObject(): targetShadow != null !",
274: LogWriter.WARN);
275: }
276: }
277: return old;
278: }
279:
280: /** */
281: protected void setOwner(User newOwner) {
282: permissions.setOwner(newOwner);
283: }
284:
285: /** */
286: protected int touchCount() {
287: return touchCount;
288: }
289:
290: /** */
291: protected boolean touched() {
292: return touched;
293: }
294:
295: /** */
296: protected long touchTime() {
297: return touchTime;
298: }
299:
300: /** */
301: protected ClusterID clusterID() {
302: return clusterID;
303: }
304:
305: /** */
306: protected void setClusterID(ClusterID _clusterID) {
307: clusterID = _clusterID;
308: }
309:
310: /**
311: */
312: protected Class objectClass() throws Exception {
313: return activatedObject().getClass();
314: }
315:
316: /**
317: * Liefert referenz auf das eigentliche objekt; das objekt wird
318: * nachgeladen, wenn es gerade nicht aktiv ist; waehrend einer
319: * update-ta wird nur der clone bearbeitet und somit auch
320: * nicht nachgeladen
321: */
322: protected OzoneCompatible activatedObject() throws Exception {
323: //meistens sollte _object initialisiert sein, deshalb wird
324: //das zuerst geprueft
325: if (target != null) {
326: return target;
327: } else if (targetShadow != null) {
328: return targetShadow;
329: } else {
330: clusterSpace.activateObject(this );
331: return target;
332: }
333: }
334:
335: /** */
336: protected synchronized void commitTarget(Transaction ta) {
337: if (targetShadow != null) {
338: target = targetShadow;
339: targetShadow = null;
340: targetBackup = null;
341: }
342: created = false;
343: lock.release(ta);
344: }
345:
346: /** */
347: protected synchronized void abortTarget(Transaction ta) {
348: if (targetShadow != null) {
349: try {
350: ObjectInputStream in = new ObjectInputStream(
351: new ByteArrayInputStream(targetBackup));
352: target = (OzoneCompatible) in.readObject();
353: in.close();
354: } catch (Exception e) {
355: //kann/darf eigentlich nicht passieren
356: env.logWriter.newEntry(this , "abortObject(): ", e,
357: LogWriter.WARN);
358: target = null;
359: }
360: targetShadow = null;
361: targetBackup = null;
362: }
363: created = false;
364: deleted = false;
365: lock.release(ta);
366: }
367:
368: /** */
369: protected synchronized void upgradeLockLevel(Transaction ta,
370: int lockLevel) throws Exception {
371: activatedObject();
372: lock.acquire(ta, Lock.LEVEL_READ);
373: if (lockLevel > Lock.LEVEL_READ) {
374: lock.acquire(ta, lockLevel);
375: // TODO: Should new created object be shadowed or not ??
376: if (!isCreated()) {
377: createShadow();
378: }
379: }
380: }
381:
382: /** */
383: protected synchronized void createShadow() throws Exception {
384: try {
385: ByteArrayOutputStream bout = new ByteArrayOutputStream();
386: ObjectOutputStream out = new ObjectOutputStream(bout);
387: out.writeObject(activatedObject());
388: out.close();
389: targetBackup = bout.toByteArray();
390: targetShadow = target;
391: target = null;
392: } catch (Exception e) {
393: // darf/kann nicht passieren
394: env.logWriter.newEntry(this , "lockWrite(): ", e,
395: LogWriter.WARN);
396: }
397: }
398:
399: /**
400: * In stream schreiben - fuer DxDiskHashtable
401: */
402: public void writeExternal(ObjectOutput out) throws IOException {
403: // if (_object != null)
404: // System.out.print ("#");
405: // else if (_targetShadow != null)
406: // System.out.print ("*");
407: // else
408: // System.out.print ("+");
409:
410: out.writeByte(subSerialVersionUID);
411:
412: out.writeObject(permissions);
413: out.writeObject(objID);
414: out.writeObject(target);
415: out.writeObject(targetShadow);
416: out.writeObject(targetBackup);
417: out.writeObject(name);
418: out.writeObject(clusterID);
419: out.writeLong(touchTime);
420: out.writeShort(touchCount);
421: out.writeBoolean(touched);
422: out.writeBoolean(created);
423: out.writeBoolean(deleted);
424: out.writeObject(lock);
425: }
426:
427: /**
428: * Aus stream lesen - fuer DxDiskHashtable. objID ist
429: * normalerweise referenz auf objID in object
430: */
431: public synchronized void readExternal(ObjectInput in)
432: throws IOException, ClassNotFoundException {
433: env = Env.currentEnv();
434: clusterSpace = ((ClassicStore) env.store).objectSpace.clusterSpace;
435:
436: byte streamVersionUID = in.readByte();
437:
438: permissions = (Permissions) in.readObject();
439: objID = (ObjectID) in.readObject();
440: target = (OzoneCompatible) in.readObject();
441: targetShadow = (OzoneCompatible) in.readObject();
442: targetBackup = (byte[]) in.readObject();
443: if (target != null) {
444: target.setContainer(this );
445: }
446: if (targetShadow != null) {
447: targetShadow.setContainer(this );
448: }
449:
450: name = (String) in.readObject();
451: clusterID = (ClusterID) in.readObject();
452: touchTime = in.readLong();
453: touchCount = in.readShort();
454: touched = in.readBoolean();
455: created = in.readBoolean();
456: deleted = in.readBoolean();
457: lock = (Lock) in.readObject();
458:
459: // if (_object != null)
460: // System.out.print (".");
461: // else if (_targetShadow != null)
462: // System.out.print (";");
463: // else
464: // System.out.print ("-");
465: }
466:
467: /**
468: * In stream schreiben. wird vom ClusterSpace verwendet.
469: */
470: protected void storeExternal(ObjectOutput out) throws IOException {
471: out.writeLong(serialVersionUID);
472: out.writeObject(permissions);
473: out.writeObject(objID);
474: out.writeObject(name);
475: out.writeObject(clusterID);
476: }
477:
478: /**
479: * Aus stream lesen - fuer ClusterSpace. objID ist
480: * normalerweise referenz auf objID in object
481: */
482: protected void loadExternal(ObjectInput in) throws IOException,
483: ClassNotFoundException {
484: env = Env.currentEnv();
485: clusterSpace = ((ClassicStore) env.store).objectSpace.clusterSpace;
486:
487: long streamSerialVersionUID = in.readLong();
488: permissions = (Permissions) in.readObject();
489: objID = (ObjectID) in.readObject();
490: name = (String) in.readObject();
491: clusterID = (ClusterID) in.readObject();
492:
493: created = false;
494: deleted = false;
495: touchTime = System.currentTimeMillis();
496: touchCount = 1;
497: touched = false;
498: lock = new DefaultLock();
499: }
500:
501: /**
502: * Search the method with the specified name and signature. Ones
503: * a method has been invoked it is stored in a global cache that holds
504: * the method objects of all database classes.
505: */
506: private Method methodFor(String methodName, String sig,
507: Object[] args) throws Exception {
508: String key = objectClass().getName() + methodName + sig;
509:
510: Method method = (Method) methodTable.elementForKey(key);
511: // Method method = null;
512: if (method == null) {
513: int argNum = args.length;
514: Class[] classes = new Class[argNum];
515: if (sig == null) {
516: //signatur aus den argumenten generieren; kann natuerlich
517: //falsch sein
518: for (int i = 0; i < argNum; i++) {
519: classes[i] = args[i].getClass();
520: }
521: } else {
522: //signatur aus dem sig-string vom proxy generieren
523: StringTokenizer st = new StringTokenizer(sig,
524: OPP.SIGNATURE_DELIMITER);
525: int i = 0;
526: while (st.hasMoreTokens()) {
527: classes[i++] = env.classManager.classForName(st
528: .nextToken());
529: }
530: // classes[i++] = Class.forName (st.nextToken());
531: }
532: method = objectClass().getMethod(methodName, classes);
533: methodTable.addForKey(method, key);
534: }
535:
536: return method;
537: }
538: }
|