Main Page | Packages | Class Hierarchy | Class List | Directories | File List | Class Members

FODBObjectDatabaseFile.java

00001 /*
00002  * OpenMobileIS - a free Java(TM) Framework for mobile applications Java(TM)
00003  * Copyright (C) 2004-2005 Philippe Delrieu
00004  * All rights reserved.
00005  * Contact: openmobileis@e-care.fr
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
00020  * USA
00021  *
00022  *  Author : Philippe Delrieu
00023  *  
00024  *  Modifications :
00025  *  2004 Creation P.Delrieu
00026  *  2004 Modified by Romain Beaugrand
00027  * 
00028  */
00029 package org.openmobileis.database.fastobjectdb.db.store;
00030 
00031 import java.io.*;
00032 
00033 import org.openmobileis.database.fastobjectdb.db.index.node.Node;
00034 import org.openmobileis.database.fastobjectdb.db.transaction.TransactionFile;
00035 
00043 public class FODBObjectDatabaseFile implements TransactionFile {
00044   //-------------------------
00045   // constants
00046   //-------------------------
00047   protected static final long DEL_LIST_END = -1l;
00048   protected static final byte IS_DELETED = 0;
00049   protected static final byte IS_ACTIVE = 1;
00050 
00051   //-------------------------
00052   // fields
00053   //-------------------------
00054   protected RandomAccessFile dataFile;
00055   protected String fileName;
00056   protected long firstDel = DEL_LIST_END;
00057 
00058   //-------------------------
00059   // constructors
00060   //-------------------------
00061   public FODBObjectDatabaseFile(String name) throws IOException {
00062     fileName = new String(name);
00063   }
00064 
00065   public FODBObjectDatabaseFile(File file) throws IOException {
00066     fileName = new String(file.getName());
00067   }
00068 
00069   protected void constructorHelper() throws IOException {
00070                 dataFile.seek(0);
00071     if (dataFile.length() == 0) {
00072       dataFile.writeLong(DEL_LIST_END);
00073       firstDel = DEL_LIST_END;
00074     } else
00075       firstDel = dataFile.readLong();
00076   }
00077 
00078   //-------------------------
00079   // implement object I/O
00080   //-------------------------
00081 
00082   // write object to current position
00083   public long writeObject(Object obj) throws IOException {
00084     ByteArrayOutputStream bytes = new ByteArrayOutputStream();
00085     ObjectOutputStream ostrm = new ObjectOutputStream(bytes);
00086     ostrm.writeObject(obj);
00087     ostrm.flush();
00088 
00089     // get the length of the output data
00090     int datalen = bytes.size(); // data length
00091     int reclen = datalen; // rec length
00092     long pos; // beginning of rec header
00093 
00094     // find someplace to put the record
00095     if (firstDel == DEL_LIST_END) {
00096       pos = dataFile.length();
00097       dataFile.seek(pos);
00098     } else { // replace a deleted record
00099       // start with first deleted record
00100       long prev = DEL_LIST_END;
00101 
00102       pos = firstDel;
00103 
00104       while (true) {
00105         dataFile.seek(pos);
00106 
00107         // read header info
00108         byte deleted = dataFile.readByte();
00109         dataFile.readInt();
00110         reclen = dataFile.readInt();
00111         //LogManager.traceDebug(0,"objectDatabasefile write deleted write length :"+reclen);
00112         long next = dataFile.readLong();
00113 
00114         // check integrity
00115         if (deleted == IS_ACTIVE)
00116           throw new IOException("corrupt delete list");
00117 
00118         // is deleted record big enough for new data?
00119         if (reclen >= datalen) {
00120           if (prev == DEL_LIST_END) {
00121             firstDel = next;
00122 
00123             // write new deleted record # at beginning of file
00124             dataFile.seek(0);
00125             dataFile.writeLong(firstDel);
00126           } else { // go back to previous record
00127             // read and change prev header
00128             dataFile.seek(prev + 1 + 4 + 4);
00129             dataFile.writeLong(next);
00130           }
00131 
00132           dataFile.seek(pos);
00133 
00134           break;
00135         }
00136 
00137         // deleted record is too small; go to next (or end)
00138         prev = pos;
00139 
00140         // do we have any more deleted records in the chain?
00141         if (next == DEL_LIST_END) {
00142           pos = dataFile.length();
00143           dataFile.seek(pos);
00144           reclen = datalen; // set new rec length Added 19/11/2003 PhD
00145           //LogManager.traceDebug(0,"objectDatabasefile  WRITE NEW NEW");
00146           break;
00147         } else
00148           pos = next;
00149       }
00150     }
00151 
00152     // patch to update the store position of page
00153     if ((obj instanceof Node)) {
00154       ((Node) obj).filePtr = pos;
00155       bytes = new ByteArrayOutputStream();
00156       ostrm = new ObjectOutputStream(bytes);
00157       ostrm.writeObject(obj);
00158       ostrm.flush();
00159       // get the length of the output data
00160       
00161       // Only changed the filePtr ... Serialization size doesn't change.
00162       //datalen = bytes.size(); // data length
00163       //reclen = datalen; // rec length
00164     }
00165     
00166     dataFile.writeByte(IS_ACTIVE);
00167     dataFile.writeInt(datalen);
00168     dataFile.writeInt(reclen);
00169 
00170     /*LogManager.traceDebug(0,"objectDatabasefile  WRITE new write length rec :"+reclen+" data : "+datalen);
00171     if (reclen < datalen)       {
00172     LogManager.traceDebug(0,"objectDatabasefile  WRITE NEW NEW");
00173     }*/
00174     dataFile.writeLong(DEL_LIST_END);
00175     dataFile.write(bytes.toByteArray());
00176 
00177     return pos;
00178   }
00179 
00180   // write an object at the current position
00181   public void rewriteObject(Object obj) throws IOException {
00182     ByteArrayOutputStream bytes = new ByteArrayOutputStream();
00183     ObjectOutputStream ostrm = new ObjectOutputStream(bytes);
00184     ostrm.writeObject(obj);
00185     ostrm.flush();
00186 
00187     // get the length of the output data
00188     int datalen = bytes.size(); // data length
00189     int reclen = datalen; // rec length
00190     
00191     //test to see if new record feet in the old record
00192     long pos = dataFile.getFilePointer();
00193     dataFile.skipBytes(5);
00194     int oldreclen = dataFile.readInt();
00195                 dataFile.seek(pos); // Go back to the beginning of the record.
00196                 
00197     if (oldreclen < datalen)    {
00198                         throw new IOException("ERROR FODBObjectDatabaseFile : rewriteObject : object to big to be rewritten." + obj.getClass().getName());
00199     }
00200 
00201     // make sure this record is marked as not deleted
00202     dataFile.writeByte(IS_ACTIVE);
00203 
00204     // write the length of the output
00205     dataFile.writeInt(datalen);
00206 
00207     // write the length of the record
00208     //dataFile.writeInt(reclen);
00209     dataFile.skipBytes(4);
00210 
00211     // write the "deleted" pointer
00212     dataFile.writeLong(DEL_LIST_END);
00213 
00214     // store the object to the actual file
00215     dataFile.write(bytes.toByteArray());
00216   }
00217 
00218   // read object from current record
00219   public Object readObject() throws IOException, ClassNotFoundException {
00220     // check record status
00221     byte deleted = dataFile.readByte();
00222 
00223     // break from loop if this is an active record
00224     if (deleted != IS_ACTIVE)
00225       throw new IOException("Try to read where there is no record");
00226     // get the length of the object
00227     int datalen = dataFile.readInt();
00228 
00229     // get length of record
00230     int reclen = dataFile.readInt();
00231 
00232     // skip the "deleted" pointer
00233     dataFile.skipBytes(8);
00234 
00235     // retrieve the object data and store it
00236     byte[] data = new byte[datalen];
00237     dataFile.readFully(data);
00238 
00239     // position pointer to beginning of next record
00240     int diff = reclen - datalen;
00241 
00242     if (diff > 0)
00243       dataFile.skipBytes(diff);
00244 
00245     ByteArrayInputStream bytes = new ByteArrayInputStream(data);
00246     ObjectInputStream istrm = new ObjectInputStream(bytes);
00247     return istrm.readObject();
00248   }
00249 
00250   // delete the current object record
00251   public void delete() throws IOException {
00252     // assume beginning of record, get pointer
00253     long pos = dataFile.getFilePointer();
00254 
00255     // is this record already deleted?
00256     byte deleted = dataFile.readByte();
00257 
00258     if (deleted == IS_DELETED)
00259       return;
00260 
00261     // back up and write new marker
00262     dataFile.seek(pos);
00263     dataFile.writeByte(IS_DELETED);
00264 
00265     // skip data length value
00266     dataFile.skipBytes(4 + 4);
00267                 dataFile.writeLong(firstDel);
00268 
00269     // now change file header
00270     firstDel = pos;
00271     dataFile.seek(0);
00272     dataFile.writeLong(firstDel);
00273   }  
00274 
00275   // go to beginning of file
00276   public void rewind() throws IOException {
00277     dataFile.seek(8);
00278   }
00279 
00280   // skip over an object record
00281   public void skip() throws IOException {
00282     // skip over parts of record header
00283     dataFile.skipBytes(1 + 4);
00284 
00285     // read record length
00286     int reclen = dataFile.readInt();
00287 
00288     // skip to beginning of next record
00289     dataFile.skipBytes(8 + reclen);
00290   }
00291 
00292   public String getFileName() {
00293     return fileName;
00294   }
00295 
00296   //--------------------------------------------
00297   // provide shells for RandomAccessFile methods
00298   //--------------------------------------------
00299   public final FileDescriptor getFD() throws IOException {
00300     return dataFile.getFD();
00301   }
00302 
00303   public long getFilePointer() throws IOException {
00304     return dataFile.getFilePointer();
00305   }
00306 
00307   public void seek(long pos) throws IOException {
00308     dataFile.seek(pos);
00309   }
00310 
00311   public long length() throws IOException {
00312     return dataFile.length();
00313   }
00314   
00315         public void close() throws IOException {
00316                         if (dataFile != null)    {
00317                                 dataFile.close();
00318                                 dataFile = null;
00319                         }
00320         }
00321   
00322         public void open() throws IOException   {
00323                 try {                   
00324                         dataFile = new RandomAccessFile(fileName, "rw");
00325                         constructorHelper();
00326                 } catch (Throwable ex) { // if an error occurs close the datafile.
00327                         try {
00328                                 if (dataFile != null) {
00329                                         dataFile.close();
00330                                 }
00331                         } catch (Throwable exi) {
00332                                 org.openmobileis.common.util.log.LogManager.traceError(0, "ObjectDatabaseFile constructorHelper error :" + exi.getMessage());
00333                         }
00334                         throw new IOException(ex.getMessage());
00335                 }
00336         }
00337 }

Generated on Thu Oct 6 10:06:32 2005 for OpenMobileIS by  doxygen 1.4.3