001: // You can redistribute this software and/or modify it under the terms of
002: // the Ozone Library 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: BLOBContainerImpl.java,v 1.1 2001/12/18 10:31:30 per_nyfelt Exp $
008:
009: package org.ozoneDB.blob;
010:
011: import org.ozoneDB.DxLib.*;
012: import org.ozoneDB.*;
013: import java.io.*;
014:
015: /**
016: * The BLOB implementation. The data are stored in several BLOBPages. The
017: * data of the BLOB can be accessed through BLOBInOutputStreams.
018: *
019: *
020: * @author <a href="http://www.softwarebuero.de/">SMB</a>
021: * @version $Revision: 1.1 $Date: 2001/12/18 10:31:30 $
022: */
023: public class BLOBContainerImpl extends OzoneObject implements
024: BLOBContainer {
025:
026: protected final static int DEFAULT_PAGE_SIZE = 32 * 1024;
027:
028: protected boolean debug = false;
029:
030: protected DxVector pages;
031:
032: protected int pageSize = DEFAULT_PAGE_SIZE;
033:
034: public BLOBContainerImpl() {
035: pages = new DxArrayBag();
036: pageSize = DEFAULT_PAGE_SIZE;
037: }
038:
039: public void init(int _pageSize) {
040: pageSize = _pageSize;
041: }
042:
043: /**
044: * Returns the available bytes of this BLOB beginning at index.
045: *
046: * NEVER WRITE ON BLOB WHILE EXECUTING THIS METHOD!
047: *
048: * @param _index the startposition
049: * @return the number of available bytes after _index
050: * @exception Exception (some kind of databaseexception ?)
051: */
052: public int available(int _index) throws Exception {
053: int pageNum = pageNum(_index);
054: int pageOff = pageOff(_index);
055: int lastNum = pages.count() - 1;
056: int result = 0;
057:
058: if (debug) {
059: System.out.println("pageNum: " + pageNum);
060: System.out.println("pageOff: " + pageOff);
061: System.out.println("lastNum: " + lastNum);
062: }
063:
064: if (pageNum <= lastNum) {
065:
066: if (pageNum < lastNum) {
067: // index is not on last page
068: // -> size of page where index points to
069: result += (pageSize - pageOff);
070: // + size of pages except startpage and last
071: result += pageSize * (lastNum - pageNum - 1);
072: // on last page now weŽll start at offset = 0
073: pageOff = 0;
074: }
075:
076: // + size of last page
077: BLOBPage lastPage = (BLOBPage) pages
078: .elementAtIndex(lastNum);
079: result += Math.max(lastPage.size() - pageOff, 0);
080: }
081:
082: if (debug) {
083: System.out
084: .println("available(): " + result + " bytes left");
085: }
086: return result;
087: }
088:
089: /**
090: * Writes the content of the Array into the BLOB starting at index.
091: *
092: * @param _index the write startposition in the BLOB
093: * @param b the bytearray to be stored
094: * @param off the startindex in the bytearray
095: * @param len the number of bytes to be written into the BLOB
096: * @exception Exception
097: */
098: public void write(int _index, byte[] b, int off, int len)
099: throws Exception {
100:
101: if (debug) {
102: System.out.println("start writing " + len
103: + " bytes into BLOB...");
104: }
105:
106: len = len == -1 ? b.length : len;
107: int pageNum;
108: int pageOff;
109:
110: while (len > 0) {
111: pageNum = pageNum(_index);
112: pageOff = pageOff(_index);
113:
114: BLOBPage page;
115: if (pageNum >= pages.size()) {
116: page = (BLOBPage) database().createObject(
117: BLOBPageImpl.class.getName());
118: page.init(pageSize);
119: pages.add(page);
120:
121: if (debug) {
122: System.out.println("\tnew Page Number " + pageNum
123: + " created.");
124: }
125: } else {
126: page = (BLOBPage) pages.elementAtIndex(pageNum);
127: }
128:
129: int writeSize = pageSize - pageOff;
130: writeSize = Math.min(len, writeSize);
131:
132: writeSize = (pageSize - page.size());
133: writeSize = Math.min(len, writeSize);
134: byte[] pageData = new byte[writeSize];
135:
136: System.arraycopy(b, off, pageData, 0, writeSize);
137: page.write(pageData, pageOff);
138:
139: _index += writeSize;
140: off += writeSize;
141: len -= writeSize;
142:
143: if (debug) {
144: System.out.println("\tactual index in BLOB: " + _index
145: + ", " + len + " bytes left to write.");
146: }
147: }
148:
149: // for the case of allowing rewrite to a BLOB we have to check, if we
150: // need to cut off pages that were used before writing this and now are
151: // left with undefined content. Else the available () method may return
152: // undefined results!
153: int lastNum;
154: pageNum = pageNum(_index);
155: while ((lastNum = (pages.count() - 1)) > pageNum) {
156: BLOBPage page = (BLOBPage) pages.elementAtIndex(lastNum);
157: database().deleteObject(page);
158: pages.deleteAtIndex(lastNum);
159:
160: if (debug) {
161: System.out.println("\tPage Number " + lastNum
162: + " deleted.");
163: }
164: }
165:
166: if (debug) {
167: System.out.println("writing into BLOB done.");
168: }
169: }
170:
171: public byte[] read(int index, int len) throws Exception {
172:
173: if (debug) {
174: System.out.println("start reading " + len
175: + " bytes from BLOB...");
176: }
177:
178: // calculate the real length
179: len = Math.min(available(index), len);
180:
181: byte[] result = new byte[len];
182: int off = 0;
183:
184: while (len > 0) {
185: int pageNum = pageNum(index);
186: int pageOff = pageOff(index);
187: int readSize = Math.min(pageSize - pageOff, len);
188: // this is correct, because the calculating of the real length
189: // saves me from reading more out of the page then it contains
190:
191: BLOBPage page = (BLOBPage) pages.elementAtIndex(pageNum);
192: // this page exists because if not, available() would have returned 0
193: // and this code is not reached.
194:
195: byte[] pageData = page.read(pageOff, readSize);
196: System.arraycopy(pageData, 0, result, off, readSize);
197:
198: index += readSize;
199: off += readSize;
200: len -= readSize;
201:
202: if (debug) {
203: System.out.println("\tpage #" + pageNum
204: + ", actual index in BLOB: " + index + ", "
205: + len + " bytes left to read.");
206: }
207: }
208:
209: if (debug) {
210: System.out.println("reading from BLOB done.");
211: }
212: return result;
213: }
214:
215: /**
216: * THIS MUST BE CALLED ON DELETE TO KILL ALL REFERENCED BLOBPAGES !
217: * (hope the database does this for me...)
218: */
219: public void onDelete() throws Exception {
220: // iterate over all pages and delete them
221: DxIterator iterator = pages.iterator();
222: BLOBPage page;
223:
224: while (iterator.next() != null) {
225: page = (BLOBPage) iterator.object();
226: database().deleteObject(page);
227: }
228: }
229:
230: protected int pageNum(int index) {
231: return index / pageSize;
232: }
233:
234: protected int pageOff(int index) {
235: return index % pageSize;
236: }
237: }
|