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: DbCacheChunk.java,v 1.2 2002/06/08 00:49:38 mediumnet Exp $
008:
009: package org.ozoneDB.core.DbRemote;
010:
011: import java.io.*;
012: import java.lang.reflect.*;
013: import org.ozoneDB.DxLib.*;
014: import org.ozoneDB.*;
015: import org.ozoneDB.core.*;
016: import org.ozoneDB.util.*;
017:
018: /**
019: * Read/write a chunk of objects from/to the server. This is used by the
020: * {@link ClientCacheDatabase} to fetch/sync objects from/to the server.
021: *
022: *
023: * @author <a href="http://www.softwarebuero.de/">SMB</a>
024: * @version $Revision: 1.2 $Date: 2002/06/08 00:49:38 $
025: */
026: public final class DbCacheChunk extends DbCommand implements
027: Externalizable {
028:
029: private final static byte MODE_READ = 1;
030: private final static byte MODE_WRITE = 2;
031:
032: private byte mode;
033:
034: private int size;
035:
036: private ObjectID rootID;
037:
038: private byte[] chunk;
039:
040: public DbCacheChunk() {
041: }
042:
043: /**
044: * Fetch objects from the server.
045: */
046: public DbCacheChunk(ObjectID _rootID, int _size) {
047: mode = MODE_READ;
048: rootID = _rootID;
049: size = _size;
050: }
051:
052: /**
053: * Store objects in the server.
054: */
055: public DbCacheChunk(byte[] _chunk) {
056: mode = MODE_WRITE;
057: chunk = _chunk;
058: }
059:
060: public void perform(Transaction ta) throws Exception {
061: env.logWriter.newEntry(this , "DbCacheChunk.perform(): mode:"
062: + mode, LogWriter.DEBUG);
063:
064: switch (mode) {
065: case MODE_READ:
066: readChunk(ta);
067: break;
068: case MODE_WRITE:
069: writeChunk(ta);
070: break;
071: default:
072: throw new RuntimeException("Unknown mode.");
073: }
074: }
075:
076: protected void readChunk(Transaction ta) throws Exception {
077: env.logWriter
078: .newEntry(this , " readChunk()", LogWriter.DEBUG3);
079:
080: DxBag bag = env.storeManager.clusterOfID(rootID);
081:
082: result = new DxArrayBag();
083:
084: DxIterator it = bag.iterator();
085: ObjectID id = null;
086: while ((id = (ObjectID) it.next()) != null) {
087: try {
088: env.logWriter.newEntry(this , "readChunk(): " + id,
089: LogWriter.DEBUG3);
090: ObjectContainer container = ta.acquireObjectAndPin(id,
091: Lock.LEVEL_READ);
092:
093: try {
094: // since the container link in the target is transient we can
095: // copy the target by just serializing it
096: CacheObjectContainer cc = new CacheObjectContainer(
097: container);
098:
099: ((DxArrayBag) result).add(cc);
100: } finally {
101: container.unpin();
102: }
103: } catch (OzoneRemoteExc e) {
104: env.logWriter.newEntry(this , " readChunk(): "
105: + e.toString(), LogWriter.DEBUG3);
106: // we don't handle ObjectNotFoundExc and such things here
107: continue;
108: }
109: }
110: }
111:
112: protected void writeChunk(Transaction ta) throws Exception {
113: env.logWriter.newEntry(this , "writeChunk(): size:"
114: + chunk.length, LogWriter.DEBUG3);
115:
116: // writeChunk can use byte[] chunks because proxies always assume
117: // that they are inside the server and so seting their link
118: // correctly, this differs from readChunk()
119:
120: ByteArrayInputStream bin = new ByteArrayInputStream(chunk);
121: ObjectInputStream in = new ObjectInputStream(bin);
122:
123: env.logWriter.newEntry(this , " available:" + bin.available(),
124: LogWriter.DEBUG3);
125: while (bin.available() > 0) {
126: CacheObjectContainer cacheContainer = (CacheObjectContainer) in
127: .readObject();
128: env.logWriter.newEntry(this , " container: id:"
129: + cacheContainer.id() + " state:"
130: + cacheContainer.state(), LogWriter.DEBUG3);
131:
132: if (cacheContainer.state() == ObjectContainer.STATE_CREATED) {
133: ObjectContainer container = ta.createObjectAndPin(null,
134: cacheContainer.access(), cacheContainer.name(),
135: null, null, cacheContainer.id());
136: try {
137: container.setTarget(cacheContainer.target());
138: } finally {
139: container.unpin();
140: }
141: } else {
142: // this throws an exception if the container has been deleted already
143: ObjectContainer container = ta.acquireObjectAndPin(
144: cacheContainer.id(), Lock.LEVEL_WRITE);
145:
146: // check the optimistic lock
147: if (container.modTime() > cacheContainer.modTime()) {
148: throw new TransactionExc(
149: "Object has been changed by another transaction.",
150: TransactionExc.OPTIMISTIC);
151: }
152:
153: if (cacheContainer.state() == ObjectContainer.STATE_DELETED) {
154: ta.deleteObject(container.id());
155: } else if (cacheContainer.state() == ObjectContainer.STATE_MODIFIED) {
156: container.setTarget(cacheContainer.target());
157:
158: // do nothing if the names are the same
159: String name = cacheContainer.name();
160: // if (!(container.name() == null && name == null || container.name().equals (name)))
161: container.nameTarget(name);
162: } else {
163: throw new RuntimeException(
164: "Wrong container state: "
165: + container.state());
166: }
167: }
168: }
169: }
170:
171: /**
172: * Recursivly search the specified object and put all found OzoneProxies
173: * in the specified deque.
174: */
175: protected void findProxies(Object obj, DxDeque deque) {
176: String name = obj != null ? obj.getClass().getName() : "(null)";
177: System.out.println("*** findProxies(): " + name);
178:
179: if (obj == null) {
180: // do nothing
181: } else if (obj instanceof OzoneProxy) {
182: deque.pushTop(((OzoneProxy) obj).remoteID());
183: } else {
184: Class cl = obj.getClass();
185: int mdf = cl.getModifiers();
186: if (Modifier.isTransient(mdf) || Modifier.isStatic(mdf)
187: || Modifier.isFinal(mdf)) {
188: // do nothing
189: System.out.println("*** transient/static/final"
190: + name);
191: } else if (cl.isPrimitive()) {
192: // do nothing
193: System.out.println("*** primitive" + name);
194: } else if (cl.isArray()) {
195: System.out.println("*** array" + name);
196: int len = Array.getLength(obj);
197: for (int j = 0; j < len; j++) {
198: Object member = Array.get(obj, j);
199: findProxies(member, deque);
200: }
201: } else {
202: Field[] fields = cl.getFields();
203: for (int i = 0; i < fields.length; i++) {
204: try {
205: System.out.println("*** "
206: + fields[i].toString());
207: Object member = fields[i].get(obj);
208: findProxies(member, deque);
209: } catch (Exception e) {
210: // should never happen
211: System.out.println("*** exception" + name);
212: }
213: }
214: }
215: }
216: }
217:
218: public void writeExternal(ObjectOutput out) throws IOException {
219: out.writeByte(mode);
220: switch (mode) {
221: case MODE_WRITE: {
222: out.writeObject(chunk);
223: break;
224: }
225: case MODE_READ: {
226: out.writeInt(size);
227: out.writeObject(rootID);
228: break;
229: }
230: default:
231: throw new RuntimeException("Unknown mode.");
232: }
233: }
234:
235: public synchronized void readExternal(ObjectInput in)
236: throws IOException, ClassNotFoundException {
237: mode = in.readByte();
238: switch (mode) {
239: case MODE_WRITE: {
240: chunk = (byte[]) in.readObject();
241: break;
242: }
243: case MODE_READ: {
244: size = in.readInt();
245: rootID = (ObjectID) in.readObject();
246: break;
247: }
248: default:
249: throw new RuntimeException("Unknown mode.");
250: }
251: }
252:
253: }
254:
255: /**
256: * @author <a href="http://www.softwarebuero.de/">SMB</a>
257: * @version $Revision: 1.2 $Date: 2002/06/08 00:49:38 $
258: */
259: final class RObjectOutputStream extends ObjectOutputStream {
260:
261: private DxDeque deque;
262:
263: public RObjectOutputStream(OutputStream out, DxDeque _deque)
264: throws IOException {
265: super (out);
266: deque = _deque;
267:
268: System.out.println(getClass().getClassLoader());
269: enableReplaceObject(true);
270: }
271:
272: protected Object replaceObject(Object obj) throws IOException {
273: String name = obj != null ? obj.getClass().getName() : "(null)";
274: System.out.println("*** replaceObject():" + name);
275:
276: if (obj instanceof OzoneProxy) {
277: System.out.println("*** proxy!");
278: deque.pushTop(((OzoneProxy) obj).remoteID());
279: }
280:
281: return obj;
282: }
283:
284: }
|