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

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     
00190     //test to see if new record feet in the old record
00191     long pos = dataFile.getFilePointer();
00192     dataFile.skipBytes(5);
00193     int oldreclen = dataFile.readInt();
00194                 dataFile.seek(pos); // Go back to the beginning of the record.
00195                 
00196     if (oldreclen < datalen)    {
00197                         throw new IOException("ERROR FODBObjectDatabaseFile : rewriteObject : object to big to be rewritten." + obj.getClass().getName());
00198     }
00199 
00200     // make sure this record is marked as not deleted
00201     dataFile.writeByte(IS_ACTIVE);
00202 
00203     // write the length of the output
00204     dataFile.writeInt(datalen);
00205 
00206     // write the length of the record
00207     //dataFile.writeInt(reclen);
00208     dataFile.skipBytes(4);
00209 
00210     // write the "deleted" pointer
00211     dataFile.writeLong(DEL_LIST_END);
00212 
00213     // store the object to the actual file
00214     dataFile.write(bytes.toByteArray());
00215   }
00216 
00217   // read object from current record
00218   public Object readObject() throws IOException, ClassNotFoundException {
00219     // check record status
00220     byte deleted = dataFile.readByte();
00221 
00222     // break from loop if this is an active record
00223     if (deleted != IS_ACTIVE)
00224       throw new IOException("Try to read where there is no record");
00225     // get the length of the object
00226     int datalen = dataFile.readInt();
00227 
00228     // get length of record
00229     int reclen = dataFile.readInt();
00230 
00231     // skip the "deleted" pointer
00232     dataFile.skipBytes(8);
00233 
00234     // retrieve the object data and store it
00235     byte[] data = new byte[datalen];
00236     dataFile.readFully(data);
00237 
00238     // position pointer to beginning of next record
00239     int diff = reclen - datalen;
00240 
00241     if (diff > 0)
00242       dataFile.skipBytes(diff);
00243 
00244     ByteArrayInputStream bytes = new ByteArrayInputStream(data);
00245     ObjectInputStream istrm = new ObjectInputStream(bytes);
00246     return istrm.readObject();
00247   }
00248 
00249   // delete the current object record
00250   public void delete() throws IOException {
00251     // assume beginning of record, get pointer
00252     long pos = dataFile.getFilePointer();
00253 
00254     // is this record already deleted?
00255     byte deleted = dataFile.readByte();
00256 
00257     if (deleted == IS_DELETED)
00258       return;
00259 
00260     // back up and write new marker
00261     dataFile.seek(pos);
00262     dataFile.writeByte(IS_DELETED);
00263 
00264     // skip data length value
00265     dataFile.skipBytes(4 + 4);
00266                 dataFile.writeLong(firstDel);
00267 
00268     // now change file header
00269     firstDel = pos;
00270     dataFile.seek(0);
00271     dataFile.writeLong(firstDel);
00272   }  
00273 
00274   // go to beginning of file
00275   public void rewind() throws IOException {
00276     dataFile.seek(8);
00277   }
00278 
00279   // skip over an object record
00280   public void skip() throws IOException {
00281     // skip over parts of record header
00282     dataFile.skipBytes(1 + 4);
00283 
00284     // read record length
00285     int reclen = dataFile.readInt();
00286 
00287     // skip to beginning of next record
00288     dataFile.skipBytes(8 + reclen);
00289   }
00290 
00291   public String getFileName() {
00292     return fileName;
00293   }
00294 
00295   //--------------------------------------------
00296   // provide shells for RandomAccessFile methods
00297   //--------------------------------------------
00298   public final FileDescriptor getFD() throws IOException {
00299     return dataFile.getFD();
00300   }
00301 
00302   public long getFilePointer() throws IOException {
00303     return dataFile.getFilePointer();
00304   }
00305 
00306   public void seek(long pos) throws IOException {
00307     dataFile.seek(pos);
00308   }
00309 
00310   public long length() throws IOException {
00311     return dataFile.length();
00312   }
00313   
00314         public void close() throws IOException {
00315                         if (dataFile != null)    {
00316                                 dataFile.close();
00317                                 dataFile = null;
00318                         }
00319         }
00320   
00321         public void open() throws IOException   {
00322                 try {                   
00323                         dataFile = new RandomAccessFile(fileName, "rw");
00324                         constructorHelper();
00325                 } catch (Throwable ex) { // if an error occurs close the datafile.
00326                         try {
00327                                 if (dataFile != null) {
00328                                         dataFile.close();
00329                                 }
00330                         } catch (Throwable exi) {
00331                                 org.openmobileis.common.util.log.LogManager.traceError(0, "ObjectDatabaseFile constructorHelper error :" + exi.getMessage());
00332                         }
00333                         throw new IOException(ex.getMessage());
00334                 }
00335         }
00336 }

Generated on Wed Dec 14 21:05:33 2005 for OpenMobileIS by  doxygen 1.4.4