Thread: AW: [OJB-developers] Re: Named Root Objects
Brought to you by:
thma
From: Mahler T. <tho...@it...> - 2002-01-15 09:29:38
|
Hi Michael, There will be a lot of people using OJB who do not use named roots. Just imagine their faces when the GC starts and deletes all their objects because they where unreferenced >:-() !!! Thus Having the GC as a separate tool is a good idea, not to say a MUST! Implementing a GC that will reclaim everything that can not be reached from a named root will not be difficult. The algorithm you describe is a simple "mark and sweep" algorithm. Would be fun to implement such a thing! cheers, Thomas > > Hi Thomas! > > I've been thinking about the GC process over the last few days. > > > Currently there is no GC implemented. > > IMHO it will be VERY difficult to have a real GC as it > would be possible > > with an OODBMS. > > It will be very difficult to decide if objects can safely > be deleted. > > > > BUT: we have been thinking of changing the semantics of > DList.remove() > > an similar methods as name roots unbind so that removed objects are > > deleted from the DB. > > A first step towards true persistence by reachability could > be to offer > offline GC. This way you don't have the to deal with objects which not > reachable from any named root object any more but are still > referenced under > another transaction that has not yet committed. The algorithm > could look > like this: > > 1. Make a list of all objects stored in the database > 2. from every named root object traverse the object graph and mark any > object you come across as being persistent > 3. delete all the objects from the database which are > currently not marked > as persistent. > > The algorithm can be implemented using recursion. In order to avoid > indefinite loops caused by cyclic references, the algorithm > has to check > whether an object under investigation is already marked. > > Another advantage is that people who do not want seamless > persistence the > "Java Way" but instead want to have a more basic level > control over their > data still have the option not to execute the garbage collector. > > What do you think about it? > > Greetings Michael > ----- Original Message ----- > From: "Thomas Mahler" <tho...@ho...> > To: "Michael Nowotny" <mic...@gm...>; "ojb" > <obj...@li...> > Sent: Wednesday, January 09, 2002 6:51 PM > Subject: Re: Named Root Objects > > > > Hi again, > > > > > > Michael Nowotny wrote: > > > > > Hi Thomas! > > > > > > Thanks for the illustration. Binding collections works > fine for me now! > > > The reason why my earlier attempt failed was that I was > still using > > > InstantDB.It seems that some transactions got only > halfway commited due > to > > > program termination following db.close(). Now I'm using > Hypersonic and > > > everything works. > > > > > > > Fine ! > > > > > > > During the course of setting up a test procedure I came > across some > strange > > > behaviour. The following code snipped throws an > ObjectNameNotBoundException. > > > > > > // fails: > > > tx = odmg.newTransaction(); > > > tx.begin(); > > > db.bind(odmg.newDList(), "MyList"); > > > db.unbind("MyList"); > > > db.bind(odmg.newDList(), "MyList"); > > > // DList list = (DList)db.lookup("MyList"); > > > tx.commit(); > > > > > > tx = odmg.newTransaction(); > > > tx.begin(); > > > DList newList = (DList)db.lookup("MyList"); > > > tx.commit(); > > > > > > Binding the same name twice within the same transaction > seems to cause > an > > > error. > > > > > > Oops, This is a bug. I'll add it to my todo list! > > > > > > This is not very important though because usually one wouldn't want > > > to bind an object to a some name and thereafter unbinding > that name > withing > > > the same transaction. > > > > > > Another question arose when I had a look at the contents > of my database. > If > > > I add content to my list which is a named root object > this content gets > > > persistent as well. That's part of persistence by > reachability. But when > I > > > unbind the root object and the content is therefore no > longer reachable, > it > > > doesn't get removed from the database but is still > present. Is there any > way > > > of performing some kind of garbage collection? > > > > > > > > > > > Currently there is no GC implemented. > > IMHO it will be VERY difficult to have a real GC as it > would be possible > > with an OODBMS. > > It will be very difficult to decide if objects can safely > be deleted. > > > > BUT: we have been thinking of changing the semantics of > DList.remove() > > an similar methods as name roots unbind so that removed objects are > > deleted from the DB. > > > > Any ideas? > > > > -- Thomas > > > > > > > > > > > Keep up the good work! > > > > > > Thanks, Michael > > > > > > ----- Original Message ----- > > > From: "Thomas Mahler" <tho...@ho...> > > > To: "Michael Nowotny" <mic...@gm...>; "ojb" > > > <obj...@li...> > > > Sent: Tuesday, January 08, 2002 8:20 PM > > > Subject: Re: Named Root Objects > > > > > > > > > > > >>Hi Michael, > > >> > > >>please see the attached Java class. > > >> > > >>You can replace the original version of > test.ojb.odmg.OdmgExamples with > > >>this new version to have it executed with the OJB JUnit tests. > > >> > > >>There is a new testMethod testNrmAndDlists that tests > your scenario. > > >>Works great! > > >> > > >>HTH, > > >> > > >>Thomas > > >> > > >>Michael Nowotny wrote: > > >> > > >> > > >>>Hi Thomas! > > >>> > > >>>Just found your OJB project on sourceforge. I think it's > great to have > > >>> > > > an > > > > > >>>open source ODMG implementation around. > > >>>Now I've got a question concerning the ODMG implemetation. > > >>>Is it possible to use a DList for example as a named root object. > > >>> > > > Binding > > > > > >>>that object to a name works but looking it up again causes an > > >>>IllegalArgumentException. > > >>> > > >>>Have you ever tried to bind a Collection. If so, I would > be grateful if > > >>> > > > you > > > > > >>>could drop me some lines of source code. > > >>> > > >>>Thanks Michael > > >>> > > >>> > > >>> > > >>> > > >>> > > >>> > > >> > > >> > > > > > > > > > > > -------------------------------------------------------------- > ------------ > -- > > > ---- > > > > > > > > > > > >>package test.ojb.odmg; > > >> > > >> > > >>import junit.framework.TestCase; > > >>import ojb.broker.Identity; > > >>import ojb.broker.PersistenceBroker; > > >>import ojb.broker.PersistenceBrokerFactory; > > >>import ojb.broker.cache.ObjectCacheFactory; > > >>import ojb.odmg.OJB; > > >>import ojb.odmg.states.ModificationState; > > >>import ojb.odmg.states.StateNewClean; > > >>import ojb.odmg.states.StateNewDirty; > > >>import org.odmg.*; > > >> > > >>import java.util.List; > > >> > > >>/** Demo Application that shows basic concepts for > Applications using > the > > >> > > > OJB ODMG > > > > > >> * implementation as an transactional object server. > > >> */ > > >>public class OdmgExamples extends TestCase > > >>{ > > >> public static void main(String[] args) > > >> { > > >> String[] arr = {CLASS.getName()}; > > >> junit.textui.TestRunner.main(arr); > > >> } > > >> > > >> private static Class CLASS = OdmgExamples.class; > > >> private String databaseName; > > >> > > >> /** > > >> * Insert the method's description here. > > >> * Creation date: (24.12.2000 00:33:40) > > >> */ > > >> public OdmgExamples(String name) > > >> { > > >> super(name); > > >> } > > >> > > >> /** > > >> * Insert the method's description here. > > >> * Creation date: (06.12.2000 21:58:53) > > >> */ > > >> public void setUp() > > >> { > > >> databaseName = > > >> > > > > PersistenceBrokerFactory.getConfiguration().getRepositoryFilename(); > > > > > >> > > >> } > > >> > > >> /** > > >> * Insert the method's description here. > > >> * Creation date: (06.12.2000 21:59:14) > > >> */ > > >> public void tearDown() > > >> { > > >> databaseName = null; > > >> } > > >> > > >> /**TestThreadsNLocks state transition of modification states*/ > > >> public void testModificationStates() > > >> { > > >> // get facade instance > > >> Implementation odmg = OJB.getInstance(); > > >> Database db = odmg.newDatabase(); > > >> //open database > > >> try > > >> { > > >> db.open(databaseName, Database.OPEN_READ_WRITE); > > >> } > > >> catch (ODMGException ex) > > >> { > > >> fail("ODMGException: " + ex.getMessage()); > > >> } > > >> ModificationState oldState = StateNewClean.getInstance(); > > >> ModificationState newState = oldState.markDirty(); > > >> assertEquals(StateNewDirty.getInstance(), newState); > > >> > > >> oldState = newState; > > >> newState = oldState.markDirty(); > > >> assertEquals(oldState, newState); > > >> > > >> > > >> // close database > > >> try > > >> { > > >> db.close(); > > >> } > > >> catch (ODMGException ex) > > >> { > > >> fail("ODMGException: " + ex.getMessage()); > > >> } > > >> > > >> } > > >> > > >> public void testOdmgSession() > > >> { > > >> // get facade instance > > >> Implementation odmg = OJB.getInstance(); > > >> Database db = odmg.newDatabase(); > > >> //open database > > >> try > > >> { > > >> db.open(databaseName, Database.OPEN_READ_WRITE); > > >> } > > >> catch (ODMGException ex) > > >> { > > >> fail("ODMGException: " + ex.getMessage()); > > >> } > > >> Transaction tx = odmg.newTransaction(); > > >> > > >> //perform transaction > > >> try > > >> { > > >> tx.begin(); > > >> > > >> Article example = new Article(); > > >> example.setArticleId(777); > > >> db.makePersistent(example); > > >> > > >> > > >> > > >> // modify Object > > >> example.setStock(333); > > >> example.addToStock(47); > > >> example.addToStock(7); > > >> example.addToStock(4); > > >> > > >> > > >> //System.out.println("now commit all changes..."); > > >> tx.commit(); > > >> } > > >> catch (Exception ex) > > >> { > > >> tx.abort(); > > >> } > > >> > > >> // close database > > >> try > > >> { > > >> db.close(); > > >> } > > >> catch (ODMGException ex) > > >> { > > >> fail("ODMGException: " + ex.getMessage()); > > >> } > > >> } > > >> > > >> public void testOQLQuery() > > >> { > > >> // get facade instance > > >> Implementation odmg = OJB.getInstance(); > > >> Database db = odmg.newDatabase(); > > >> //open database > > >> try > > >> { > > >> db.open(databaseName, Database.OPEN_READ_WRITE); > > >> } > > >> catch (ODMGException ex) > > >> { > > >> fail("ODMGException: " + ex.getMessage()); > > >> } > > >> Transaction tx = odmg.newTransaction(); > > >> > > >> //perform transaction > > >> try > > >> { > > >> tx.begin(); > > >> > > >> > > >> OQLQuery query = odmg.newOQLQuery(); > > >> query.create("select anArticle from " + > > >> > > > Article.class.getName() + " where articleId = 7"); > > > > > >> List results = (List) query.execute(); > > >> > > >> Article a = (Article) results.get(0); > > >> > > >> > > >> // cross check with PersistenceBroker lookup > > >> // 1. get OID > > >> Article example = new Article(); > > >> example.setArticleId(7); > > >> Identity oid = new Identity(example); > > >> // 2. lookup object by OID > > >> PersistenceBroker broker = > OJB.getInstance().getBroker(); > > >> broker.clearCache(); > > >> Article b = (Article) broker.getObjectByIdentity(oid); > > >> > > >> assertEquals("should be same object", a, b); > > >> > > >> //System.out.println("now commit all changes..."); > > >> tx.commit(); > > >> } > > >> catch (Exception ex) > > >> { > > >> tx.abort(); > > >> fail("ODMGException: " + ex.getMessage()); > > >> } > > >> > > >> // close database > > >> try > > >> { > > >> db.close(); > > >> } > > >> catch (ODMGException ex) > > >> { > > >> fail("ODMGException: " + ex.getMessage()); > > >> } > > >> } > > >> > > >> public void testNrmAndDlists() > > >> { > > >> // get facade instance > > >> Implementation odmg = OJB.getInstance(); > > >> Database db = odmg.newDatabase(); > > >> //open database > > >> try > > >> { > > >> db.open(databaseName, Database.OPEN_READ_WRITE); > > >> } > > >> catch (ODMGException ex) > > >> { > > >> fail("ODMGException: " + ex.getMessage()); > > >> } > > >> Transaction tx = odmg.newTransaction(); > > >> > > >> //perform transaction > > >> try > > >> { > > >> tx.begin(); > > >> > > >> > > >> OQLQuery query = odmg.newOQLQuery(); > > >> query.create("select x from " + > Article.class.getName() + " > > >> > > > where productGroupId = 7"); > > > > > >> DList results = (DList) query.execute(); > > >> > > >> > > >> int originalSize = results.size(); > > >> > > >> OJB.getLogger().info(results); > > >> > > >> String name = "gimme fruits !"; > > >> > > >> db.bind(results, name); > > >> tx.commit(); > > >> > > >> // clear the cache to make sure things are > loaded from RDBMS > ! > > >> OJB.getInstance().getBroker().clearCache(); > > >> > > >> tx = odmg.newTransaction(); > > >> tx.begin(); > > >> > > >> // look it up again > > >> DList newResults = (DList) db.lookup(name); > > >> > > >> assertEquals(originalSize,newResults.size()); > > >> OJB.getLogger().info(results); > > >> > > >> tx.commit(); > > >> > > >> > > >> } > > >> catch (Throwable t) > > >> { > > >> tx.abort(); > > >> fail("ODMGException: " + t.getMessage()); > > >> } > > >> > > >> // close database > > >> try > > >> { > > >> db.close(); > > >> } > > >> catch (ODMGException ex) > > >> { > > >> fail("ODMGException: " + ex.getMessage()); > > >> } > > >> } > > >> > > >> > > >> > > >> public void testOQLQueryBind() > > >> { > > >> // get facade instance > > >> Implementation odmg = OJB.getInstance(); > > >> Database db = odmg.newDatabase(); > > >> //open database > > >> try > > >> { > > >> db.open(databaseName, Database.OPEN_READ_WRITE); > > >> } > > >> catch (ODMGException ex) > > >> { > > >> fail("ODMGException: " + ex.getMessage()); > > >> } > > >> Transaction tx = odmg.newTransaction(); > > >> > > >> //perform transaction > > >> try > > >> { > > >> tx.begin(); > > >> > > >> > > >> OQLQuery query = odmg.newOQLQuery(); > > >> query.create("select anArticle from " + > > >> > > > Article.class.getName() + " where articleId = $678"); > > > > > >> query.bind(new Integer(7)); > > >> > > >> List results = (List) query.execute(); > > >> > > >> Article a = (Article) results.get(0); > > >> > > >> //crosscheck with PersistenceBroker lookup > > >> // 1. get OID > > >> Article example = new Article(); > > >> example.setArticleId(7); > > >> Identity oid = new Identity(example); > > >> > > >> ObjectCacheFactory.getObjectCache().clear(); > > >> // 2. lookup object by OID > > >> PersistenceBroker broker = > OJB.getInstance().getBroker(); > > >> broker.clearCache(); > > >> Article b = (Article) broker.getObjectByIdentity(oid); > > >> > > >> assertEquals("should be same object", a, b); > > >> > > >> //System.out.println("now commit all changes..."); > > >> tx.commit(); > > >> } > > >> catch (Exception ex) > > >> { > > >> tx.abort(); > > >> fail("ODMGException: " + ex.getMessage()); > > >> } > > >> > > >> // close database > > >> try > > >> { > > >> db.close(); > > >> } > > >> catch (ODMGException ex) > > >> { > > >> fail("ODMGException: " + ex.getMessage()); > > >> } > > >> } > > >> > > >> public void tesOQLQueryOnCollections() > > >> { > > >> // get facade instance > > >> Implementation odmg = OJB.getInstance(); > > >> Database db = odmg.newDatabase(); > > >> //open database > > >> try > > >> { > > >> db.open(databaseName, Database.OPEN_READ_WRITE); > > >> } > > >> catch (ODMGException ex) > > >> { > > >> fail("ODMGException: " + ex.getMessage()); > > >> } > > >> Transaction tx = odmg.newTransaction(); > > >> > > >> //perform transaction > > >> try > > >> { > > >> tx.begin(); > > >> OQLQuery query = odmg.newOQLQuery(); > > >> query.create("select aLotOfArticles from " + > > >> > > > Article.class.getName() + " where productGroupId = 4"); > > > > > >> DCollection results = (DCollection) query.execute(); > > >> results = results.query("price > 35"); > > >> > > >> // now perform control query > > >> query = odmg.newOQLQuery(); > > >> query.create("select aLotOfArticles from " + > > >> > > > Article.class.getName() + " where productGroupId = 4 and > price > 35"); > > > > > >> DCollection check = (DCollection) query.execute(); > > >> > > >> assertEquals(results, check); > > >> > > >> > > >> tx.commit(); > > >> } > > >> catch (Exception ex) > > >> { > > >> tx.abort(); > > >> ex.printStackTrace(); > > >> fail("ODMGException: " + ex.getMessage()); > > >> } > > >> > > >> // close database > > >> try > > >> { > > >> db.close(); > > >> } > > >> catch (ODMGException ex) > > >> { > > >> fail("ODMGException: " + ex.getMessage()); > > >> } > > >> } > > >> > > >> > > >> /**try to open non-existing db*/ > > >> public void tesWrongDbName() > > >> { > > >> // get facade instance > > >> OJB objectserver = OJB.getInstance(); > > >> Database db = objectserver.newDatabase(); > > >> > > >> //try open database with non existing repository file: > > >> String wrongDatabaseName = "ThereIsNoSuchFile"; > > >> try > > >> { > > >> db.open(wrongDatabaseName, Database.OPEN_READ_WRITE); > > >> fail("should not be able to open database " + > > >> > > > wrongDatabaseName); > > > > > >> } > > >> catch (ODMGException ex) > > >> { > > >> return; > > >> } > > >> } > > >>} > > >> > > >> > > > > > > > > > > > > > > > > > > > > > _______________________________________________ > Objectbridge-developers mailing list > Obj...@li... > https://lists.sourceforge.net/lists/listinfo/objectbridge-developers > |
From: Michael N. <mic...@gm...> - 2002-01-15 21:23:10
|
Hi Thomas! Is there a way to let OJB create and remove tables automatically. In my opinion such a feature could come in quite handy while developing your app. JBoss has such an option. An XSLT Stylesheet that transforms the repository XML into sql statements could look like this: <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="text" omit-xml-declaration="yes" indent="yes"/> <xsl:template match="/"> <xsl:for-each select="MappingRepository/ClassDescriptor"> <!-- generate sql drop table statement--> <xsl:text>drop table </xsl:text><xsl:value-of select="table.name"/><xsl:text>; </xsl:text> <!-- generate sql create table statement--> <xsl:text>create table </xsl:text><xsl:value-of select="table.name"/><xsl:text> ( </xsl:text> <xsl:for-each select="FieldDescriptor"> <xsl:value-of select="column.name"/> <xsl:text> </xsl:text> <xsl:value-of select="jdbc_type"/> <xsl:if test="PrimaryKey='true'"> <xsl:text> NOT NULL PRIMARY KEY</xsl:text> </xsl:if> <xsl:text> </xsl:text> </xsl:for-each> <xsl:text>); </xsl:text> </xsl:for-each> </xsl:template> </xsl:stylesheet> What still remains to be done is inserting switches that indicate whether you want automatic table creation/removal enabled or not. It might be possible to change the repository.dtd accordingly. Another thing I don't know is whether jdbc types are automatically mapped to sql types by the jdbc driver. Greetings, Michael ----- Original Message ----- From: "Mahler Thomas" <tho...@it...> To: "'Michael Nowotny'" <mic...@gm...>; "ojb" <obj...@li...> Sent: Tuesday, January 15, 2002 10:29 AM Subject: AW: [OJB-developers] Re: Named Root Objects > Hi Michael, > > > There will be a lot of people using OJB who do not use named roots. > Just imagine their faces when the GC starts and deletes all their objects > because they where unreferenced >:-() !!! > > Thus Having the GC as a separate tool is a good idea, not to say a MUST! > > Implementing a GC that will reclaim everything that can not be reached from > a named root will not be difficult. > The algorithm you describe is a simple "mark and sweep" algorithm. Would be > fun to implement such a thing! > > cheers, > > Thomas > > > > > > Hi Thomas! > > > > I've been thinking about the GC process over the last few days. > > > > > Currently there is no GC implemented. > > > IMHO it will be VERY difficult to have a real GC as it > > would be possible > > > with an OODBMS. > > > It will be very difficult to decide if objects can safely > > be deleted. > > > > > > BUT: we have been thinking of changing the semantics of > > DList.remove() > > > an similar methods as name roots unbind so that removed objects are > > > deleted from the DB. > > > > A first step towards true persistence by reachability could > > be to offer > > offline GC. This way you don't have the to deal with objects which not > > reachable from any named root object any more but are still > > referenced under > > another transaction that has not yet committed. The algorithm > > could look > > like this: > > > > 1. Make a list of all objects stored in the database > > 2. from every named root object traverse the object graph and mark any > > object you come across as being persistent > > 3. delete all the objects from the database which are > > currently not marked > > as persistent. > > > > The algorithm can be implemented using recursion. In order to avoid > > indefinite loops caused by cyclic references, the algorithm > > has to check > > whether an object under investigation is already marked. > > > > Another advantage is that people who do not want seamless > > persistence the > > "Java Way" but instead want to have a more basic level > > control over their > > data still have the option not to execute the garbage collector. > > > > What do you think about it? > > > > > > Greetings Michael > > ----- Original Message ----- > > From: "Thomas Mahler" <tho...@ho...> > > To: "Michael Nowotny" <mic...@gm...>; "ojb" > > <obj...@li...> > > Sent: Wednesday, January 09, 2002 6:51 PM > > Subject: Re: Named Root Objects > > > > > > > Hi again, > > > > > > > > > Michael Nowotny wrote: > > > > > > > Hi Thomas! > > > > > > > > Thanks for the illustration. Binding collections works > > fine for me now! > > > > The reason why my earlier attempt failed was that I was > > still using > > > > InstantDB.It seems that some transactions got only > > halfway commited due > > to > > > > program termination following db.close(). Now I'm using > > Hypersonic and > > > > everything works. > > > > > > > > > > Fine ! > > > > > > > > > > During the course of setting up a test procedure I came > > across some > > strange > > > > behaviour. The following code snipped throws an > > ObjectNameNotBoundException. > > > > > > > > // fails: > > > > tx = odmg.newTransaction(); > > > > tx.begin(); > > > > db.bind(odmg.newDList(), "MyList"); > > > > db.unbind("MyList"); > > > > db.bind(odmg.newDList(), "MyList"); > > > > // DList list = (DList)db.lookup("MyList"); > > > > tx.commit(); > > > > > > > > tx = odmg.newTransaction(); > > > > tx.begin(); > > > > DList newList = (DList)db.lookup("MyList"); > > > > tx.commit(); > > > > > > > > Binding the same name twice within the same transaction > > seems to cause > > an > > > > error. > > > > > > > > > Oops, This is a bug. I'll add it to my todo list! > > > > > > > > > This is not very important though because usually one wouldn't want > > > > to bind an object to a some name and thereafter unbinding > > that name > > withing > > > > the same transaction. > > > > > > > > Another question arose when I had a look at the contents > > of my database. > > If > > > > I add content to my list which is a named root object > > this content gets > > > > persistent as well. That's part of persistence by > > reachability. But when > > I > > > > unbind the root object and the content is therefore no > > longer reachable, > > it > > > > doesn't get removed from the database but is still > > present. Is there any > > way > > > > of performing some kind of garbage collection? > > > > > > > > > > > > > > > > Currently there is no GC implemented. > > > IMHO it will be VERY difficult to have a real GC as it > > would be possible > > > with an OODBMS. > > > It will be very difficult to decide if objects can safely > > be deleted. > > > > > > BUT: we have been thinking of changing the semantics of > > DList.remove() > > > an similar methods as name roots unbind so that removed objects are > > > deleted from the DB. > > > > > > Any ideas? > > > > > > -- Thomas > > > > > > > > > > > > > > > > Keep up the good work! > > > > > > > > Thanks, Michael > > > > > > > > ----- Original Message ----- > > > > From: "Thomas Mahler" <tho...@ho...> > > > > To: "Michael Nowotny" <mic...@gm...>; "ojb" > > > > <obj...@li...> > > > > Sent: Tuesday, January 08, 2002 8:20 PM > > > > Subject: Re: Named Root Objects > > > > > > > > > > > > > > > >>Hi Michael, > > > >> > > > >>please see the attached Java class. > > > >> > > > >>You can replace the original version of > > test.ojb.odmg.OdmgExamples with > > > >>this new version to have it executed with the OJB JUnit tests. > > > >> > > > >>There is a new testMethod testNrmAndDlists that tests > > your scenario. > > > >>Works great! > > > >> > > > >>HTH, > > > >> > > > >>Thomas > > > >> > > > >>Michael Nowotny wrote: > > > >> > > > >> > > > >>>Hi Thomas! > > > >>> > > > >>>Just found your OJB project on sourceforge. I think it's > > great to have > > > >>> > > > > an > > > > > > > >>>open source ODMG implementation around. > > > >>>Now I've got a question concerning the ODMG implemetation. > > > >>>Is it possible to use a DList for example as a named root object. > > > >>> > > > > Binding > > > > > > > >>>that object to a name works but looking it up again causes an > > > >>>IllegalArgumentException. > > > >>> > > > >>>Have you ever tried to bind a Collection. If so, I would > > be grateful if > > > >>> > > > > you > > > > > > > >>>could drop me some lines of source code. > > > >>> > > > >>>Thanks Michael > > > >>> > > > >>> > > > >>> > > > >>> > > > >>> > > > >>> > > > >> > > > >> > > > > > > > > > > > > > > > > -------------------------------------------------------------- > > ------------ > > -- > > > > ---- > > > > > > > > > > > > > > > >>package test.ojb.odmg; > > > >> > > > >> > > > >>import junit.framework.TestCase; > > > >>import ojb.broker.Identity; > > > >>import ojb.broker.PersistenceBroker; > > > >>import ojb.broker.PersistenceBrokerFactory; > > > >>import ojb.broker.cache.ObjectCacheFactory; > > > >>import ojb.odmg.OJB; > > > >>import ojb.odmg.states.ModificationState; > > > >>import ojb.odmg.states.StateNewClean; > > > >>import ojb.odmg.states.StateNewDirty; > > > >>import org.odmg.*; > > > >> > > > >>import java.util.List; > > > >> > > > >>/** Demo Application that shows basic concepts for > > Applications using > > the > > > >> > > > > OJB ODMG > > > > > > > >> * implementation as an transactional object server. > > > >> */ > > > >>public class OdmgExamples extends TestCase > > > >>{ > > > >> public static void main(String[] args) > > > >> { > > > >> String[] arr = {CLASS.getName()}; > > > >> junit.textui.TestRunner.main(arr); > > > >> } > > > >> > > > >> private static Class CLASS = OdmgExamples.class; > > > >> private String databaseName; > > > >> > > > >> /** > > > >> * Insert the method's description here. > > > >> * Creation date: (24.12.2000 00:33:40) > > > >> */ > > > >> public OdmgExamples(String name) > > > >> { > > > >> super(name); > > > >> } > > > >> > > > >> /** > > > >> * Insert the method's description here. > > > >> * Creation date: (06.12.2000 21:58:53) > > > >> */ > > > >> public void setUp() > > > >> { > > > >> databaseName = > > > >> > > > > > > PersistenceBrokerFactory.getConfiguration().getRepositoryFilename(); > > > > > > > >> > > > >> } > > > >> > > > >> /** > > > >> * Insert the method's description here. > > > >> * Creation date: (06.12.2000 21:59:14) > > > >> */ > > > >> public void tearDown() > > > >> { > > > >> databaseName = null; > > > >> } > > > >> > > > >> /**TestThreadsNLocks state transition of modification states*/ > > > >> public void testModificationStates() > > > >> { > > > >> // get facade instance > > > >> Implementation odmg = OJB.getInstance(); > > > >> Database db = odmg.newDatabase(); > > > >> //open database > > > >> try > > > >> { > > > >> db.open(databaseName, Database.OPEN_READ_WRITE); > > > >> } > > > >> catch (ODMGException ex) > > > >> { > > > >> fail("ODMGException: " + ex.getMessage()); > > > >> } > > > >> ModificationState oldState = StateNewClean.getInstance(); > > > >> ModificationState newState = oldState.markDirty(); > > > >> assertEquals(StateNewDirty.getInstance(), newState); > > > >> > > > >> oldState = newState; > > > >> newState = oldState.markDirty(); > > > >> assertEquals(oldState, newState); > > > >> > > > >> > > > >> // close database > > > >> try > > > >> { > > > >> db.close(); > > > >> } > > > >> catch (ODMGException ex) > > > >> { > > > >> fail("ODMGException: " + ex.getMessage()); > > > >> } > > > >> > > > >> } > > > >> > > > >> public void testOdmgSession() > > > >> { > > > >> // get facade instance > > > >> Implementation odmg = OJB.getInstance(); > > > >> Database db = odmg.newDatabase(); > > > >> //open database > > > >> try > > > >> { > > > >> db.open(databaseName, Database.OPEN_READ_WRITE); > > > >> } > > > >> catch (ODMGException ex) > > > >> { > > > >> fail("ODMGException: " + ex.getMessage()); > > > >> } > > > >> Transaction tx = odmg.newTransaction(); > > > >> > > > >> //perform transaction > > > >> try > > > >> { > > > >> tx.begin(); > > > >> > > > >> Article example = new Article(); > > > >> example.setArticleId(777); > > > >> db.makePersistent(example); > > > >> > > > >> > > > >> > > > >> // modify Object > > > >> example.setStock(333); > > > >> example.addToStock(47); > > > >> example.addToStock(7); > > > >> example.addToStock(4); > > > >> > > > >> > > > >> //System.out.println("now commit all changes..."); > > > >> tx.commit(); > > > >> } > > > >> catch (Exception ex) > > > >> { > > > >> tx.abort(); > > > >> } > > > >> > > > >> // close database > > > >> try > > > >> { > > > >> db.close(); > > > >> } > > > >> catch (ODMGException ex) > > > >> { > > > >> fail("ODMGException: " + ex.getMessage()); > > > >> } > > > >> } > > > >> > > > >> public void testOQLQuery() > > > >> { > > > >> // get facade instance > > > >> Implementation odmg = OJB.getInstance(); > > > >> Database db = odmg.newDatabase(); > > > >> //open database > > > >> try > > > >> { > > > >> db.open(databaseName, Database.OPEN_READ_WRITE); > > > >> } > > > >> catch (ODMGException ex) > > > >> { > > > >> fail("ODMGException: " + ex.getMessage()); > > > >> } > > > >> Transaction tx = odmg.newTransaction(); > > > >> > > > >> //perform transaction > > > >> try > > > >> { > > > >> tx.begin(); > > > >> > > > >> > > > >> OQLQuery query = odmg.newOQLQuery(); > > > >> query.create("select anArticle from " + > > > >> > > > > Article.class.getName() + " where articleId = 7"); > > > > > > > >> List results = (List) query.execute(); > > > >> > > > >> Article a = (Article) results.get(0); > > > >> > > > >> > > > >> // cross check with PersistenceBroker lookup > > > >> // 1. get OID > > > >> Article example = new Article(); > > > >> example.setArticleId(7); > > > >> Identity oid = new Identity(example); > > > >> // 2. lookup object by OID > > > >> PersistenceBroker broker = > > OJB.getInstance().getBroker(); > > > >> broker.clearCache(); > > > >> Article b = (Article) broker.getObjectByIdentity(oid); > > > >> > > > >> assertEquals("should be same object", a, b); > > > >> > > > >> //System.out.println("now commit all changes..."); > > > >> tx.commit(); > > > >> } > > > >> catch (Exception ex) > > > >> { > > > >> tx.abort(); > > > >> fail("ODMGException: " + ex.getMessage()); > > > >> } > > > >> > > > >> // close database > > > >> try > > > >> { > > > >> db.close(); > > > >> } > > > >> catch (ODMGException ex) > > > >> { > > > >> fail("ODMGException: " + ex.getMessage()); > > > >> } > > > >> } > > > >> > > > >> public void testNrmAndDlists() > > > >> { > > > >> // get facade instance > > > >> Implementation odmg = OJB.getInstance(); > > > >> Database db = odmg.newDatabase(); > > > >> //open database > > > >> try > > > >> { > > > >> db.open(databaseName, Database.OPEN_READ_WRITE); > > > >> } > > > >> catch (ODMGException ex) > > > >> { > > > >> fail("ODMGException: " + ex.getMessage()); > > > >> } > > > >> Transaction tx = odmg.newTransaction(); > > > >> > > > >> //perform transaction > > > >> try > > > >> { > > > >> tx.begin(); > > > >> > > > >> > > > >> OQLQuery query = odmg.newOQLQuery(); > > > >> query.create("select x from " + > > Article.class.getName() + " > > > >> > > > > where productGroupId = 7"); > > > > > > > >> DList results = (DList) query.execute(); > > > >> > > > >> > > > >> int originalSize = results.size(); > > > >> > > > >> OJB.getLogger().info(results); > > > >> > > > >> String name = "gimme fruits !"; > > > >> > > > >> db.bind(results, name); > > > >> tx.commit(); > > > >> > > > >> // clear the cache to make sure things are > > loaded from RDBMS > > ! > > > >> OJB.getInstance().getBroker().clearCache(); > > > >> > > > >> tx = odmg.newTransaction(); > > > >> tx.begin(); > > > >> > > > >> // look it up again > > > >> DList newResults = (DList) db.lookup(name); > > > >> > > > >> assertEquals(originalSize,newResults.size()); > > > >> OJB.getLogger().info(results); > > > >> > > > >> tx.commit(); > > > >> > > > >> > > > >> } > > > >> catch (Throwable t) > > > >> { > > > >> tx.abort(); > > > >> fail("ODMGException: " + t.getMessage()); > > > >> } > > > >> > > > >> // close database > > > >> try > > > >> { > > > >> db.close(); > > > >> } > > > >> catch (ODMGException ex) > > > >> { > > > >> fail("ODMGException: " + ex.getMessage()); > > > >> } > > > >> } > > > >> > > > >> > > > >> > > > >> public void testOQLQueryBind() > > > >> { > > > >> // get facade instance > > > >> Implementation odmg = OJB.getInstance(); > > > >> Database db = odmg.newDatabase(); > > > >> //open database > > > >> try > > > >> { > > > >> db.open(databaseName, Database.OPEN_READ_WRITE); > > > >> } > > > >> catch (ODMGException ex) > > > >> { > > > >> fail("ODMGException: " + ex.getMessage()); > > > >> } > > > >> Transaction tx = odmg.newTransaction(); > > > >> > > > >> //perform transaction > > > >> try > > > >> { > > > >> tx.begin(); > > > >> > > > >> > > > >> OQLQuery query = odmg.newOQLQuery(); > > > >> query.create("select anArticle from " + > > > >> > > > > Article.class.getName() + " where articleId = $678"); > > > > > > > >> query.bind(new Integer(7)); > > > >> > > > >> List results = (List) query.execute(); > > > >> > > > >> Article a = (Article) results.get(0); > > > >> > > > >> //crosscheck with PersistenceBroker lookup > > > >> // 1. get OID > > > >> Article example = new Article(); > > > >> example.setArticleId(7); > > > >> Identity oid = new Identity(example); > > > >> > > > >> ObjectCacheFactory.getObjectCache().clear(); > > > >> // 2. lookup object by OID > > > >> PersistenceBroker broker = > > OJB.getInstance().getBroker(); > > > >> broker.clearCache(); > > > >> Article b = (Article) broker.getObjectByIdentity(oid); > > > >> > > > >> assertEquals("should be same object", a, b); > > > >> > > > >> //System.out.println("now commit all changes..."); > > > >> tx.commit(); > > > >> } > > > >> catch (Exception ex) > > > >> { > > > >> tx.abort(); > > > >> fail("ODMGException: " + ex.getMessage()); > > > >> } > > > >> > > > >> // close database > > > >> try > > > >> { > > > >> db.close(); > > > >> } > > > >> catch (ODMGException ex) > > > >> { > > > >> fail("ODMGException: " + ex.getMessage()); > > > >> } > > > >> } > > > >> > > > >> public void tesOQLQueryOnCollections() > > > >> { > > > >> // get facade instance > > > >> Implementation odmg = OJB.getInstance(); > > > >> Database db = odmg.newDatabase(); > > > >> //open database > > > >> try > > > >> { > > > >> db.open(databaseName, Database.OPEN_READ_WRITE); > > > >> } > > > >> catch (ODMGException ex) > > > >> { > > > >> fail("ODMGException: " + ex.getMessage()); > > > >> } > > > >> Transaction tx = odmg.newTransaction(); > > > >> > > > >> //perform transaction > > > >> try > > > >> { > > > >> tx.begin(); > > > >> OQLQuery query = odmg.newOQLQuery(); > > > >> query.create("select aLotOfArticles from " + > > > >> > > > > Article.class.getName() + " where productGroupId = 4"); > > > > > > > >> DCollection results = (DCollection) query.execute(); > > > >> results = results.query("price > 35"); > > > >> > > > >> // now perform control query > > > >> query = odmg.newOQLQuery(); > > > >> query.create("select aLotOfArticles from " + > > > >> > > > > Article.class.getName() + " where productGroupId = 4 and > > price > 35"); > > > > > > > >> DCollection check = (DCollection) query.execute(); > > > >> > > > >> assertEquals(results, check); > > > >> > > > >> > > > >> tx.commit(); > > > >> } > > > >> catch (Exception ex) > > > >> { > > > >> tx.abort(); > > > >> ex.printStackTrace(); > > > >> fail("ODMGException: " + ex.getMessage()); > > > >> } > > > >> > > > >> // close database > > > >> try > > > >> { > > > >> db.close(); > > > >> } > > > >> catch (ODMGException ex) > > > >> { > > > >> fail("ODMGException: " + ex.getMessage()); > > > >> } > > > >> } > > > >> > > > >> > > > >> /**try to open non-existing db*/ > > > >> public void tesWrongDbName() > > > >> { > > > >> // get facade instance > > > >> OJB objectserver = OJB.getInstance(); > > > >> Database db = objectserver.newDatabase(); > > > >> > > > >> //try open database with non existing repository file: > > > >> String wrongDatabaseName = "ThereIsNoSuchFile"; > > > >> try > > > >> { > > > >> db.open(wrongDatabaseName, Database.OPEN_READ_WRITE); > > > >> fail("should not be able to open database " + > > > >> > > > > wrongDatabaseName); > > > > > > > >> } > > > >> catch (ODMGException ex) > > > >> { > > > >> return; > > > >> } > > > >> } > > > >>} > > > >> > > > >> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > _______________________________________________ > > Objectbridge-developers mailing list > > Obj...@li... > > https://lists.sourceforge.net/lists/listinfo/objectbridge-developers > > > |
From: Thomas M. <tho...@ho...> - 2002-01-18 18:31:53
|
Hi Michael, please excuse me for getting back to you so late. I have been quite busy and your mail got lost in my inbox... Michael Nowotny wrote: > Hi Thomas! > > Is there a way to let OJB create and remove tables automatically. In my > opinion such a feature could come in quite handy while developing your app. That's a good idea. I have been dreaming of full forward/reverse engineering support in OJB. There should be support for: 1. automatic generation (and maybe also execution) of SQL DDL (and a repository.xml) from a object model. 2. it should be possible to reverse-engineer database table to persistent classes and a repository.xml. 3. It should be possible to write a repository.xml and have both Java classes and DB tables generated. 4. convienant support to build mapping from existing Object Model on existing tables (maybe similar to the TOPLink mapping workbench). Maybe XSL transformation is a good vehicle for 1.-3. ?! > JBoss has such an option. An XSLT Stylesheet that transforms > the repository XML into sql statements could look like this: > > <?xml version="1.0"?> > <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > version="1.0"> > <xsl:output method="text" omit-xml-declaration="yes" indent="yes"/> > > <xsl:template match="/"> > <xsl:for-each select="MappingRepository/ClassDescriptor"> > <!-- generate sql drop table statement--> > <xsl:text>drop table </xsl:text><xsl:value-of > select="table.name"/><xsl:text>; > </xsl:text> > <!-- generate sql create table statement--> > <xsl:text>create table </xsl:text><xsl:value-of > select="table.name"/><xsl:text> ( > </xsl:text> > <xsl:for-each select="FieldDescriptor"> > <xsl:value-of select="column.name"/> > <xsl:text> </xsl:text> > <xsl:value-of select="jdbc_type"/> > <xsl:if test="PrimaryKey='true'"> > <xsl:text> NOT NULL PRIMARY KEY</xsl:text> > </xsl:if> > <xsl:text> > </xsl:text> > </xsl:for-each> > <xsl:text>); > > </xsl:text> > </xsl:for-each> > </xsl:template> > </xsl:stylesheet> > > What still remains to be done is inserting switches that indicate whether > you want automatic table creation/removal enabled or not. It might be > possible to change > the repository.dtd accordingly. that's a cool approach ! I tried it and the output looks quite promising already. But there are some caveats: 1. Multiple classes maybe mapped on one and the same table. They may even use different columns ! 2. OJB allows to have compound primary key which are not handled properly by the above xsl stylesheet. 3. The current DTD does not contain size information (e.g. only VARCHAR but not VARCHAR(255) !) having automatic creation configurable is a good idea! In some production evironment it won't be viable to have tables changed dynamically ! > Another thing I don't know is whether jdbc types are automatically mapped to > sql types by the jdbc driver. This is another caveat. It would be possible to deduce the type info for a given JDBC ResultSet column from the respective MetaData object. But to be compatible with a large number of RDBMS OJB relies on an explicit type declaration in each FieldDescriptor. (Thus we can e.g. have a VARCHAR in the DB, but a byte[] in the Java Object) Maybe it's a good idea to have the type info optional, as it is sufficient for most cases. Feel free to work on this and contribute some code if you like! You have so many creative ideas, why not let some of them come OJB reality ;-) cu, Thomas ps.: have you been digging into the GC idea further ? |