/* * Copyright (C) 2004 The Concord Consortium, Inc., * 10 Concord Crossing, Concord, MA 01742 * * Web Site: http://www.concord.org * Email: info@concord.org * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * END LICENSE */ /* * Last modification information: * $Revision: 1.14 $ * $Date: 2007-10-05 18:03:39 $ * $Author: scytacki $ * * Licence Information * Copyright 2004 The Concord Consortium */ package org.concord.otrunk.datamodel.fs; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.URI; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Properties; import org.concord.framework.otrunk.OTID; import org.concord.framework.otrunk.OTPackage; import org.concord.otrunk.datamodel.BlobResource; import org.concord.otrunk.datamodel.OTDataCollection; import org.concord.otrunk.datamodel.OTDataList; import org.concord.otrunk.datamodel.OTDataMap; import org.concord.otrunk.datamodel.OTDataObject; import org.concord.otrunk.datamodel.OTDataObjectType; import org.concord.otrunk.datamodel.OTDataPropertyReference; import org.concord.otrunk.datamodel.OTDatabase; import org.concord.otrunk.datamodel.OTIDFactory; import org.concord.otrunk.datamodel.OTUUID; /** * FsDatabase * Class name and description * * Date created: Aug 22, 2004 * * @author scott<p> * */ public class FsDatabase implements OTDatabase { // This needs to be initialized from files in the db folder // and on closing it should be written out again HashMap<OTID, FsDataObject> dbIndex = new HashMap<OTID, FsDataObject>(); // This needs to be initialized and saved in the db folder // index file. OTID rootId; File databaseFolder; public FsDatabase(File dbFolder) throws Exception { databaseFolder = dbFolder; load(dbFolder); } protected void load(File dbFolder) throws Exception { if (!dbFolder.exists()) { dbFolder.mkdirs(); } if (!dbFolder.isDirectory()) { throw new Exception("Database folder is not a folder, " + "it is a regular file"); } File dbPropFile = new File(dbFolder, "db.prop"); if (dbPropFile.exists() ) { Properties dbProp = new Properties(); FileInputStream dbPropStream = new FileInputStream(dbPropFile); dbProp.load(dbPropStream); dbPropStream.close(); String rootStr = dbProp.getProperty("root-id", null); if (rootStr != null) { rootId = OTIDFactory.createOTID(rootStr); } } System.out.println("loading objects"); File [] children = dbFolder.listFiles(); for (int i=0; i<children.length; i++) { String childName = children[i].getName(); if(childName.equals("db.prop") || childName.equals("CVS")) { continue; } FsDataObject obj; OTID childId = OTIDFactory.createOTID(childName); try { FileInputStream inStream = new FileInputStream(children[i]); ObjectInputStream objInStream = new ObjectInputStream(inStream); obj = (FsDataObject)objInStream.readObject(); inStream.close(); } catch (Exception e) { System.err.println("Error loading obj: " + childId); e.printStackTrace(); continue; } if(!childId.equals(obj.getGlobalId())) { throw new Exception ("Mismatched ids"); } dbIndex.put(childId, obj); } } protected void store(File dbFolder) throws Exception { if (!dbFolder.exists()) { dbFolder.mkdirs(); } if (!dbFolder.isDirectory()) { throw new Exception("Database folder is not a folder, " + "it is a regular file"); } if(rootId != null) { File dbPropFile = new File(dbFolder, "db.prop"); FileOutputStream outStream = new FileOutputStream(dbPropFile); Properties dbProp = new Properties(); dbProp.put("root-id", rootId.toExternalForm()); dbProp.store(outStream, ""); outStream.close(); } // TODO we should store each of these elements in a // temporary place incase there is an error writting // an object. Currently when there is an error writting an element // the whole database is corrupted. Collection<FsDataObject> values = dbIndex.values(); for (FsDataObject dataObject : values) { OTID id = dataObject.getGlobalId(); String fileName = id.toExternalForm(); File dataFile = new File(dbFolder, fileName); FileOutputStream outStream = new FileOutputStream(dataFile); ObjectOutputStream objOutStream = new ObjectOutputStream(outStream); objOutStream.writeObject(dataObject); objOutStream.close(); } } /* * This returns a classless dataobject currently this is only used * by the user data object code * (non-Javadoc) * @see org.concord.otrunk.OTDatabase#createDataObject() */ public OTDataObject createDataObject(OTDataObjectType type) throws Exception { OTID id = OTUUID.createOTUUID(); return createDataObject(type, id); } /** * This should verify the id wasn't used before */ public OTDataObject createDataObject(OTDataObjectType type, OTID id) throws Exception { FsDataObject dataObject = new FsDataObject(type, (OTUUID)id, this); dataObject.creationInit(); FsDataObject oldValue = dbIndex.put(dataObject.getGlobalId(), dataObject); if(oldValue != null) { dbIndex.put(dataObject.getGlobalId(), oldValue); throw new Exception("repeated unique id"); } return dataObject; } public OTDataObject createDataObject(byte [] objectBytes) throws Exception { ByteArrayInputStream inStream = new ByteArrayInputStream(objectBytes); ObjectInputStream objInStream = new ObjectInputStream(inStream); OTDataObject obj = (OTDataObject)objInStream.readObject(); inStream.close(); return obj; } public void importDataObject(OTDataObject obj) { dbIndex.put(obj.getGlobalId(), (FsDataObject)obj); } /* (non-Javadoc) * @see org.concord.otrunk.OTDatabase#createCollection(java.lang.Class) */ public OTDataCollection createCollection(OTDataObject parent, Class<?> collectionClass) throws Exception { if(collectionClass.equals(OTDataList.class)) { return new FsDataList((FsDataObject)parent); } else if(collectionClass.equals(OTDataMap.class)) { return new FsDataMap((FsDataObject)parent); } // TODO Auto-generated method stub return null; } /* (non-Javadoc) * @see org.concord.otrunk.OTDatabase#getRoot() */ public OTDataObject getRoot() throws Exception { if (rootId == null) { return null; } return getOTDataObject(null, rootId); } /* (non-Javadoc) * @see org.concord.otrunk.datamodel.OTDatabase#setRoot(org.concord.otrunk.datamodel.OTDataObject) */ public void setRoot(OTID rootId) throws Exception { this.rootId = rootId; } public byte [] getObjectBytes(OTDataObject dObj) throws Exception { ByteArrayOutputStream outStream = new ByteArrayOutputStream(); ObjectOutputStream objOutStream = new ObjectOutputStream(outStream); objOutStream.writeObject(dObj); objOutStream.close(); return outStream.toByteArray(); } /* (non-Javadoc) * @see org.concord.otrunk.OTDatabase#getOTDataObject(org.concord.otrunk.OTDataObject, org.doomdark.uuid.UUID) */ public OTDataObject getOTDataObject(OTDataObject dataParent, OTID childID) throws Exception { return dbIndex.get(childID); } /* (non-Javadoc) * @see org.concord.otrunk.datamodel.OTDatabase#contains(org.concord.framework.otrunk.OTID) */ public boolean contains(OTID id) { return dbIndex.containsKey(id); } /* (non-Javadoc) * @see org.concord.otrunk.OTDatabase#close() */ public void close() { try { store(databaseFolder); } catch (Exception e) { e.printStackTrace(); } } /* (non-Javadoc) * @see org.concord.otrunk.datamodel.OTDatabase#getRelativeOTID(org.concord.framework.otrunk.OTID, java.lang.String) */ public OTID getRelativeOTID(OTID parent, String relativePath) { throw new UnsupportedOperationException("FsDatabase does not support getRelativeOTID not supported"); } /* (non-Javadoc) * @see org.concord.otrunk.datamodel.OTDatabase#createBlobResource(java.net.URL) */ public BlobResource createBlobResource(URL url) { // TODO Auto-generated method stub return null; } /* (non-Javadoc) * @see org.concord.otrunk.datamodel.OTDatabase#getPackageClasses() */ public ArrayList<Class<? extends OTPackage>> getPackageClasses() { // TODO Auto-generated method stub return null; } public OTID getDatabaseId() { // TODO Auto-generated method stub return null; } public URI getURI() { // TODO Auto-generated method stub return null; } public HashMap<OTID, FsDataObject> getDataObjects() { return dbIndex; } public ArrayList<OTDataPropertyReference> getOutgoingReferences(OTID otid) { throw new UnsupportedOperationException("not implemented yet"); } public ArrayList<OTDataPropertyReference> getIncomingReferences(OTID otid) { throw new UnsupportedOperationException("not implemented yet"); } public void recordReference(OTID parentID, OTID childID, String property) { throw new UnsupportedOperationException("not implemented yet"); } public void recordReference(OTDataObject parent, OTDataObject child, String property) { throw new UnsupportedOperationException("not implemented yet"); } public void removeReference(OTDataObject parent, OTDataObject child) { throw new UnsupportedOperationException("not implemented yet"); } public void removeReference(OTID parentID, OTID childID) { throw new UnsupportedOperationException("not implemented yet"); } }