Hi All,
As I've stated in earlier e-mail to the list, I've had pretty good luck
with Castor. I recently embarked on changing our current database layout
so that it would better match the object layout/DTD/XSD for our project's
events. So here's the approach I took.
1) wrote an SQL script to create a test database
2) wrote a mapping XML to marshal to/from the database
3) wrote an XSD so that the Castor SourceGenerator could provide the code.
The SourceGenerator provides methods for "collections" in the form of
void setXXX( YYY[] array );
YYY[] getXXX( );
Well I noticed that the mapping.dtd for the "field" element allows the
attribute "collection" that may be one of:
array
vector
hashtable
collection
set
map
I chose to use the "array" setting since that matched what was
generated by the SourceGenerator. I figured this was the ultimate in being
able to manage changes. In effect I would have castor generate my
source classes, XML, and SQL.... This would have really cut down on my
work if it were not for one simple fact: Arrays are not implemented
yet!
After my initial disallusionment passed I hunkered down and attempted to
write the missing code. I seemed to be having a fair bit of success, except
that I'm stuck and I don't know how to proceed. I could really use some
help from those who understand the source better than I.
I've attached the context diff of my changes to the latest CVS source tree
for castor (see castor.patch). These can be applied using:
cvs co castor
cd castor
patch -p1 < ../castor.patch
Once the changes are applied, build and then unpack the compressed tar
into another directory.
mkdir test
cd test
tar xzvf ../testset.tgz
java org.exolab.castor.builder.SourceGenerator \
-i schema/mapping/event.xsd \
-package org.opennms.netmgt.xml.event \
-types j2 \
-dest srcgen
mkdir work/classes
cd srcgen
find org -name \*.java -print > listing
javac -g -d ../work/classes @listing
cd ..
cp schema/mapping/event.xml \
work/classes/org/opennms/netmgt/xml/event
javac -g -d work/classes schema/mapping/Test.java
At this point all you need is a database.xml where the test program
can locate it, and a database of course. I'm using PostgreSQL 7.1
and have used the 'schema/mapping/event.sql' to create the tables.
I get the following results on the first run:
----------------------------------
org.exolab.castor.jdo.PersistenceException: Nested error: No class found for
org.opennms.netmgt.xml.event.Parameter.
No class found for org.opennms.netmgt.xml.event.Parameter.
at org.postgresql.Connection.putObject(Connection.java:812)
at org.postgresql.jdbc2.PreparedStatement.setObject(PreparedStatement.java:596)
at org.exolab.castor.jdo.engine.SQLEngine.load(SQLEngine.java:999)
at org.exolab.castor.persist.ClassMolder.load(ClassMolder.java:646)
at org.exolab.castor.persist.LockEngine.load(LockEngine.java:361)
at
org.exolab.castor.persist.TransactionContext.load(TransactionContext.java:545)
at
org.exolab.castor.persist.TransactionContext.load(TransactionContext.java:479)
at org.exolab.castor.persist.ClassMolder.load(ClassMolder.java:742)
at org.exolab.castor.persist.LockEngine.load(LockEngine.java:361)
at
org.exolab.castor.persist.TransactionContext.load(TransactionContext.java:545)
at org.exolab.castor.persist.QueryResults.fetch(QueryResults.java:229)
at
org.exolab.castor.jdo.engine.OQLQueryImpl$OQLEnumeration.hasMore(OQLQueryImpl.java:573)
at
org.exolab.castor.jdo.engine.OQLQueryImpl$OQLEnumeration.hasMore(OQLQueryImpl.java:556)
at org.opennms.netmgt.db.Test.run(Test.java:132)
at org.opennms.netmgt.db.Test.main(Test.java:35)
----------------------------------
On the second run I get:
----------------------------------
Begin transaction
<?xml version="1.0"?>
<event id="1">
<create-time>2001-07-31 10:29:00 </create-time>
<uei>http://uei.opennms.org/event/bogus</uei>
<source>fake.opennms.org</source>
<time>2001-07-31 10:28:59 </time>
<snmp id="1">
<enterprise-id>.1.3.6.1.4.3.1.3.2.2.1</enterprise-id>
<version>SNMPv1</version>
<generic>6</generic>
<specific>32</specific>
</snmp>
<parameter event-id="1" name="retries" type="string" encoding="text"
id="1">3</parameter>
<parameter event-id="1" name="timeout" type="string" encoding="text"
id="2">2000</parameter>
</event>
<event id="1">
<create-time>2001-07-31 10:29:00 </create-time>
<uei>http://uei.opennms.org/event/bogus</uei>
<source>fake.opennms.org</source>
<time>2001-07-31 10:28:59 </time>
<snmp id="1">
<enterprise-id>.1.3.6.1.4.3.1.3.2.2.1</enterprise-id>
<version>SNMPv1</version>
<generic>6</generic>
<specific>32</specific>
</snmp>
<parameter event-id="1" name="retries" type="string" encoding="text"
id="1">3</parameter>
<parameter event-id="1" name="timeout" type="string" encoding="text"
id="2">2000</parameter>
</event>
org.exolab.castor.jdo.PersistenceException: Nested error: No class found for
org.opennms.netmgt.xml.event.Parameter.
No class found for org.opennms.netmgt.xml.event.Parameter.
at org.postgresql.Connection.putObject(Connection.java:812)
at org.postgresql.jdbc2.PreparedStatement.setObject(PreparedStatement.java:596)
at org.exolab.castor.jdo.engine.SQLEngine.load(SQLEngine.java:999)
at org.exolab.castor.persist.ClassMolder.load(ClassMolder.java:646)
at org.exolab.castor.persist.LockEngine.load(LockEngine.java:361)
at
org.exolab.castor.persist.TransactionContext.load(TransactionContext.java:545)
at
org.exolab.castor.persist.TransactionContext.load(TransactionContext.java:479)
at org.exolab.castor.persist.ClassMolder.load(ClassMolder.java:742)
at org.exolab.castor.persist.LockEngine.load(LockEngine.java:361)
at
org.exolab.castor.persist.TransactionContext.load(TransactionContext.java:545)
at org.exolab.castor.persist.QueryResults.fetch(QueryResults.java:229)
at
org.exolab.castor.jdo.engine.OQLQueryImpl$OQLEnumeration.hasMore(OQLQueryImpl.java:573)
at
org.exolab.castor.jdo.engine.OQLQueryImpl$OQLEnumeration.hasMore(OQLQueryImpl.java:556)
at org.opennms.netmgt.db.Test.run(Test.java:132)
at org.opennms.netmgt.db.Test.main(Test.java:35)
----------------------------------
So it does appear to be working to a limited degree. Any
help would be greatly appreciated.
Weave
diff -ur --exclude=CVS
castor/src/main/org/exolab/castor/builder/castorbuilder.properties
castor.new/src/main/org/exolab/castor/builder/castorbuilder.properties
--- castor/src/main/org/exolab/castor/builder/castorbuilder.properties Wed Jul 11
07:12:09 2001
+++ castor.new/src/main/org/exolab/castor/builder/castorbuilder.properties Tue
+Jul 24 05:06:09 2001
@@ -8,7 +8,7 @@
# when enabled. This will change in the future when we introduce
# fine grained control over each class and it's properties.
#
-#org.exolab.castor.builder.boundproperties=true
+org.exolab.castor.builder.boundproperties=true
# Java class mapping of <xsd:element>'s and <xsd:complexType>'s
#
@@ -22,13 +22,13 @@
# XML namespace mapping to Java packages
#
#org.exolab.castor.builder.nspackages=\
- http://www.xyz.com/schemas/project=com.xyz.schemas.project,\
- http://www.xyz.com/schemas/person=com.xyz.schemas.person
+# http://www.xyz.com/schemas/project=com.xyz.schemas.project,\
+# http://www.xyz.com/schemas/person=com.xyz.schemas.person
# Set to true if you want to generate the equals method
# for each generated class
# false by default
-#org.exolab.castor.builder.equalsmethod=true
+org.exolab.castor.builder.equalsmethod=true
# Set to true if you want to use Object Wrappers instead
# of primitives (e.g Float instead of float).
diff -ur --exclude=CVS castor/src/main/org/exolab/castor/castor.properties
castor.new/src/main/org/exolab/castor/castor.properties
--- castor/src/main/org/exolab/castor/castor.properties Wed Jan 10 21:24:35 2001
+++ castor.new/src/main/org/exolab/castor/castor.properties Mon Jul 30 16:44:31
+2001
@@ -62,7 +62,7 @@
# True if all documents should be indented on output by default
#
-#org.exolab.castor.indent=true
+org.exolab.castor.indent=true
# True if xml documents should be validated by the SAX Parser
diff -ur --exclude=CVS castor/src/main/org/exolab/castor/persist/ClassMolder.java
castor.new/src/main/org/exolab/castor/persist/ClassMolder.java
--- castor/src/main/org/exolab/castor/persist/ClassMolder.java Mon Jul 23 19:13:06
2001
+++ castor.new/src/main/org/exolab/castor/persist/ClassMolder.java Wed Aug 1
+13:55:28 2001
@@ -46,7 +46,7 @@
package org.exolab.castor.persist;
-
+import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
@@ -1555,7 +1555,7 @@
if ( collection == null )
return new ArrayList(0);
- if ( collection instanceof Map ) {
+ else if ( collection instanceof Map ) {
if ( orgIds == null || orgIds.size() == 0 ) {
if ( collection == null )
return new ArrayList(0);
@@ -1574,7 +1574,7 @@
return added;
}
- if ( collection instanceof Collection ) {
+ else if ( collection instanceof Collection ) {
if ( orgIds == null || orgIds.size() == 0 ) {
if ( collection == null )
return new ArrayList(0);
@@ -1597,6 +1597,34 @@
return added;
}
+ else if ( collection instanceof Object[] ) {
+ if ( orgIds == null || orgIds.size() == 0 ) {
+ if ( collection == null )
+ return new ArrayList(0);
+ else
+ {
+ Object[] sx = (Object[]) collection;
+ Collection c = new ArrayList(sx.length);
+ for(int x = 0; x < sx.length; x++)
+ c.add(sx[x]);
+ return c;
+ }
+ }
+
+ if ( collection == null )
+ return new ArrayList(0);
+
+ Object[] newValues = (Object[]) collection;
+ ArrayList added = new ArrayList( newValues.length );
+ for(int x = 0; x < newValues.length; x++) {
+ Object newValue = newValues[x];
+ Object newId = ch.getIdentity( tx, newValue );
+ if ( newId == null || !orgIds.contains( newId ) )
+ added.add( newValue );
+ }
+ return added;
+ }
+
throw new IllegalArgumentException( "Collection type
"+collection.getClass().getName()+" is not supported!" );
}
@@ -1612,8 +1640,7 @@
else
return orgIds;
}
-
- if ( collection instanceof Map ) {
+ else if ( collection instanceof Map ) {
if ( orgIds == null || orgIds.size() == 0 )
return new ArrayList(0);
@@ -1627,8 +1654,7 @@
}
return removed;
}
-
- if ( collection instanceof Collection ) {
+ else if ( collection instanceof Collection ) {
if ( orgIds == null || orgIds.size() == 0 )
return new ArrayList(0);
@@ -1637,21 +1663,45 @@
ArrayList removed = new ArrayList(0);
// make a new map of key and value of the new collection
- HashMap newMap = new HashMap();
+ HashSet newSet = new HashSet();
Iterator newColItor = newCol.iterator();
while ( newColItor.hasNext() ) {
Object newObject = newColItor.next();
Object newId = ch.getIdentity( tx, newObject );
if ( newId != null )
- newMap.put( newId, newObject );
+ newSet.add( newId );
}
while ( orgItor.hasNext() ) {
Object id = orgItor.next();
- if ( !newMap.containsKey( id ) )
+ if ( !newSet.contains( id ) )
removed.add( id );
}
return removed;
}
+ else if( collection instanceof Object[] ) {
+ if( orgIds == null || orgIds.size() == 0 )
+ return new ArrayList(0);
+
+ Object[] newCol = (Object[]) collection;
+ int newColNdx = 0;
+ Iterator orgItor = orgIds.iterator();
+ ArrayList removed = new ArrayList(0);
+
+ // make a new map of key and value of the new collection
+ HashSet newSet = new HashSet();
+ while(newColNdx < newCol.length) {
+ Object newObject = newCol[newColNdx++];
+ Object newId = ch.getIdentity( tx, newObject );
+ if ( newId != null )
+ newSet.add( newId );
+ }
+ while ( orgItor.hasNext() ) {
+ Object id = orgItor.next();
+ if ( !newSet.contains( id ) )
+ removed.add( id );
+ }
+ return removed;
+ }
throw new IllegalArgumentException( "Collection type
"+collection.getClass().getName()+" is not supported!" );
}
@@ -2870,6 +2920,20 @@
return ((Collection) o).iterator();
} else if ( o instanceof Map ) {
return ((Map) o).values().iterator();
+ } else if ( o instanceof Object[] ) {
+ final Object[] _inner_src = (Object[])o;
+ return new Iterator() {
+ private int _x = 0;
+ public boolean hasNext() {
+ return (_x < _inner_src.length);
+ }
+ public Object next() {
+ return _inner_src[_x++];
+ }
+ public void remove() {
+ throw new UnsupportedOperationException("array removal not
+supported!");
+ }
+ };
} else {
throw new IllegalArgumentException();
}
@@ -2905,7 +2969,14 @@
idList.add( itor.next() );
}
return idList;
- } else {
+ } else if ( col instanceof Object[] ) {
+ ArrayList idList = new ArrayList();
+ Object[] src = (Object[])col;
+ for(int x = 0; x < src.length; x++)
+ idList.add( src[x] );
+ return idList;
+ }
+ else {
throw new IllegalArgumentException("A Collection or Map is expected!");
}
}
@@ -2952,6 +3023,18 @@
return new MapProxy( fm, object, cl, new HashMap() );
} else if ( cls == Map.class ) {
return new MapProxy( fm, object, cl, new HashMap() );
+ } else if ( cls == Object[].class ) {
+ try {
+ Class ref;
+ if( cl == null )
+ ref =
+ClassLoader.getSystemClassLoader().loadClass(fm.getTypeName());
+ else
+ ref = cl.loadClass(fm.getTypeName());
+ return new ArrayProxy( fm, object, cl, (Object[])
+Array.newInstance(ref, 0) );
+ }
+ catch(ClassNotFoundException cnfE) {
+ throw new IllegalArgumentException("Collection Proxy could not load
+class type " + fm.getTypeName());
+ }
} else {
throw new IllegalArgumentException("Collection Proxy doesn't exist for it
type");
}
@@ -3005,6 +3088,49 @@
_fm.setValue( _object, _map, _cl );
}
+ }
+
+ private static class ArrayProxy extends CollectionProxy {
+ private Object[] _array;
+ private FieldMolder _fm;
+ private Object _object;
+ private ClassLoader _cl;
+ private ArrayProxy( FieldMolder fm, Object object, ClassLoader cl, Object[]
+array ) {
+ _cl = cl;
+ _fm = fm;
+ _array = array;
+ _object = object;
+ }
+ Object getCollection() {
+ return _array;
+ }
+ void add( Object key, Object value ) {
+ if ( !_fm.isAddable() )
+ {
+ if(_array != null)
+ {
+ Object[] dst = (Object[]) Array.newInstance(value.getClass(),
+_array.length+1);
+ System.arraycopy(_array,
+ 0,
+ dst,
+ 0,
+ _array.length);
+ dst[_array.length] = value;
+ _array = dst;
+ }
+ else
+ {
+ _array = (Object[]) Array.newInstance(value.getClass(), 1);
+ _array[0] = value;
+ }
+ }
+ else
+ _fm.addValue( _object, value, _cl );
+ }
+ void close() {
+ if ( !_fm.isAddable() )
+ _fm.setValue( _object, _array, _cl );
+ }
}
}
diff -ur --exclude=CVS castor/src/main/org/exolab/castor/persist/FieldMolder.java
castor.new/src/main/org/exolab/castor/persist/FieldMolder.java
--- castor/src/main/org/exolab/castor/persist/FieldMolder.java Thu Jul 26 14:35:33
2001
+++ castor.new/src/main/org/exolab/castor/persist/FieldMolder.java Wed Aug 1
+11:50:34 2001
@@ -123,6 +123,11 @@
return "FieldMolder of "+_eMold.getName()+".set"+_fieldName+"("+_fType+"
"+_fieldName+")";
}
+ public String getTypeName()
+ {
+ return _fType;
+ }
+
/*
void setRelationDescriptor( RelationDescriptor rd ) throws MappingException {
_loader = new SQLRelationLoader( rd, _eMold.getName() );
testset.tgz