You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by am...@apache.org on 2005/12/18 19:04:52 UTC

svn commit: r357484 - in /geronimo/branches/1.0/modules/connector-builder/src: java/org/apache/geronimo/connector/deployment/jsr88/ test-resources/ test/org/apache/geronimo/connector/deployment/jsr88/

Author: ammulder
Date: Sun Dec 18 10:04:45 2005
New Revision: 357484

URL: http://svn.apache.org/viewcvs?rev=357484&view=rev
Log:
Fixes to JSR-88 DConfigBeans for connectors (and thus DB pool portlet):
 - Don't write out config settings with a value of "null" (as opposed to
   the current behavior of writing with "nil=true" which blows up)
   GERONIMO-1382
 - Add test for this, which also involves being able to read a Geronimo
   deployment plan into the DConfigBeans successfully (GERONIMO-1383)
 - Add some missing JavaDoc headers
Fix for DB pool portlet so that it doesn't NPE on user or password of null

Added:
    geronimo/branches/1.0/modules/connector-builder/src/test-resources/plan-with-nulls.xml   (with props)
Modified:
    geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ConfigPropertySetting.java
    geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ConnectionDefinition.java
    geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ConnectionDefinitionInstance.java
    geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/Connector15DCBRoot.java
    geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ConnectorDCB.java
    geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ResourceAdapter.java
    geronimo/branches/1.0/modules/connector-builder/src/test/org/apache/geronimo/connector/deployment/jsr88/Connector15DCBTest.java

Modified: geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ConfigPropertySetting.java
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ConfigPropertySetting.java?rev=357484&r1=357483&r2=357484&view=diff
==============================================================================
--- geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ConfigPropertySetting.java (original)
+++ geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ConfigPropertySetting.java Sun Dec 18 10:04:45 2005
@@ -36,9 +36,9 @@
         super(null);
     }
 
-    public ConfigPropertySetting(DDBean configProperty, GerConfigPropertySettingType property) {
+    public ConfigPropertySetting(DDBean configProperty, GerConfigPropertySettingType property, boolean setDefault) {
         super(null);
-        configure(configProperty, property);
+        configure(configProperty, property, setDefault);
     }
 
     protected GerConfigPropertySettingType getPropertySetting() {
@@ -49,14 +49,18 @@
         return configProperty;
     }
 
-    void configure(DDBean configProperty, GerConfigPropertySettingType property) {
+    void configure(DDBean configProperty, GerConfigPropertySettingType property, boolean setDefault) {
         this.configProperty = configProperty;
         setXmlObject(property);
         final String name = configProperty.getText("config-property-name")[0];
         getPropertySetting().setName(name);
-        String[] test = configProperty.getText("config-property-value");
-        if(test != null && test.length == 1) {
-            getPropertySetting().setStringValue(test[0]);
+        if(setDefault) {
+            String[] test = configProperty.getText("config-property-value");
+            if(test != null && test.length == 1) {
+                getPropertySetting().setStringValue(test[0]);
+            } else {
+                getPropertySetting().setStringValue(null);
+            }
         }
     }
 
@@ -74,7 +78,7 @@
     }
 
     public String getValue() {
-        return getPropertySetting().getStringValue();
+        return getPropertySetting().isNil() ? null : getPropertySetting().getStringValue();
     }
 
     public void setValue(String value) {

Modified: geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ConnectionDefinition.java
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ConnectionDefinition.java?rev=357484&r1=357483&r2=357484&view=diff
==============================================================================
--- geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ConnectionDefinition.java (original)
+++ geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ConnectionDefinition.java Sun Dec 18 10:04:45 2005
@@ -19,6 +19,8 @@
 import java.util.Set;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.Map;
+import java.util.HashMap;
 import javax.enterprise.deploy.model.DDBean;
 import org.apache.geronimo.deployment.plugin.XmlBeanSupport;
 import org.apache.geronimo.xbeans.geronimo.GerConnectionDefinitionType;
@@ -26,6 +28,13 @@
 import org.apache.xmlbeans.SchemaTypeLoader;
 
 /**
+ * Represents /connector/resourceadapter/outbound-resourceadapter/connection-definition
+ * in the Geronimo Connector deployment plan.  A Geronimo connection definition
+ * corresponds to a ra.xml connection definition (though there may be several
+ * Geronimo CDs for each ra.xml CD so this cannot be a DConfigBean [which would
+ * require a 1:1 mapping]).  Each Geronimo connection definition may have one
+ * or more instances with different config property settings, etc.
+ *
  * @version $Rev$ $Date$
  */
 public class ConnectionDefinition extends XmlBeanSupport {
@@ -48,11 +57,26 @@
     void configure(DDBean resourceAdapter, GerConnectionDefinitionType definition) {
         this.resourceAdapter = resourceAdapter;
         setXmlObject(definition);
-        //todo: initialize connectiondefinition-instance from definition
+        //todo: handle unmatched interfaces below
+        instances = new ConnectionDefinitionInstance[definition.getConnectiondefinitionInstanceArray().length];
+        DDBean[] beans = resourceAdapter.getChildBean("outbound-resourceadapter/connection-definition");
+        DDBean match = null;
+        for (int i = 0; i < beans.length; i++) {
+            DDBean bean = beans[i];
+            if(bean.getText("connectionfactory-interface")[0].equals(definition.getConnectionfactoryInterface())) {
+                match = bean;
+                break;
+            }
+        }
+        for (int i = 0; i < instances.length; i++) {
+            GerConnectiondefinitionInstanceType gerInstance = definition.getConnectiondefinitionInstanceArray()[i];
+            instances[i] = new ConnectionDefinitionInstance(match, gerInstance);
+        }
     }
 
     // ----------------------- JavaBean Properties for connection-definition ----------------------
 
+    //todo: instead of String, make this an Enum type aware of the interfaces available in the J2EE DD
     public String getConnectionFactoryInterface() {
         return getConnectionDefinition().getConnectionfactoryInterface();
     }

Modified: geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ConnectionDefinitionInstance.java
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ConnectionDefinitionInstance.java?rev=357484&r1=357483&r2=357484&view=diff
==============================================================================
--- geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ConnectionDefinitionInstance.java (original)
+++ geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ConnectionDefinitionInstance.java Sun Dec 18 10:04:45 2005
@@ -73,9 +73,33 @@
         return (GerConnectiondefinitionInstanceType) getXmlObject();
     }
 
+    void clearNullSettings() {
+        List list = new ArrayList();
+        for (int i = 0; i < settings.length; i++) {
+            ConfigPropertySetting setting = settings[i];
+            if(setting.getValue() != null) {
+                list.add(setting);
+            }
+        }
+        settings = (ConfigPropertySetting[]) list.toArray(new ConfigPropertySetting[list.size()]);
+        GerConnectiondefinitionInstanceType instance = getConnectionInstance();
+        for (int i = instance.getConfigPropertySettingArray().length-1; i>=0; --i) {
+            GerConfigPropertySettingType type = instance.getConfigPropertySettingArray(i);
+            if(type.isNil() || type.getStringValue() == null) {
+                instance.removeConfigPropertySetting(i);
+            }
+        }
+    }
+
+    void reconfigure() {
+        configure(connectionDefinition, getConnectionInstance());
+    }
+
     void configure(DDBean connectionDefinition, GerConnectiondefinitionInstanceType definition) {
+        ConfigPropertySetting[] old = null;
         if(this.connectionDefinition != null) {
             this.connectionDefinition.removeXpathListener("config-property", xpathListener);
+            old = settings;
         }
         this.connectionDefinition = connectionDefinition;
         setXmlObject(definition);
@@ -93,7 +117,7 @@
             GerConfigPropertySettingType setting = previous[i];
             DDBean ddBean = (DDBean) byName.remove(setting.getName());
             if(ddBean != null) {
-                list.add(new ConfigPropertySetting(ddBean, setting));
+                list.add(new ConfigPropertySetting(ddBean, setting, false));
             } else {
                 System.out.println("Ignoring connectiondefinition-instance/config-setting "+setting.getName()+" (no matching config-property in J2EE DD)");
                 //todo: delete it from the XMLBeans tree
@@ -102,16 +126,19 @@
         for (Iterator it = byName.keySet().iterator(); it.hasNext();) {
             String name = (String) it.next();
             DDBean bean = (DDBean) byName.get(name);
-            list.add(new ConfigPropertySetting(bean, getConnectionInstance().addNewConfigPropertySetting()));
+            list.add(new ConfigPropertySetting(bean, getConnectionInstance().addNewConfigPropertySetting(), true));
         }
         settings = (ConfigPropertySetting[]) list.toArray(new ConfigPropertySetting[list.size()]);
+        if(old != null) {
+            pcs.firePropertyChange("configPropertySetting", old, settings);
+        }
         if(connectionDefinition != null) {
             connectionDefinition.addXpathListener("config-property", xpathListener);
         }
         if(connectionDefinition != null) {
             DDBean parent = connectionDefinition.getChildBean("..")[0];
-            ConnectionManager old = manager;
-            if(old == null) {
+            ConnectionManager oldMgr = manager;
+            if(oldMgr == null) {
                 if(definition.getConnectionmanager() != null) {
                     manager = new ConnectionManager(parent, definition.getConnectionmanager());
                 } else {
@@ -124,7 +151,7 @@
                     manager.configure(parent, definition.addNewConnectionmanager());
                 }
             }
-            pcs.firePropertyChange("connectionManager", old, manager);
+            pcs.firePropertyChange("connectionManager", oldMgr, manager);
         }
     }
 

Modified: geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/Connector15DCBRoot.java
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/Connector15DCBRoot.java?rev=357484&r1=357483&r2=357484&view=diff
==============================================================================
--- geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/Connector15DCBRoot.java (original)
+++ geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/Connector15DCBRoot.java Sun Dec 18 10:04:45 2005
@@ -18,16 +18,28 @@
 
 import java.io.InputStream;
 import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Arrays;
 import javax.enterprise.deploy.model.DDBeanRoot;
 import javax.enterprise.deploy.model.DDBean;
 import javax.enterprise.deploy.spi.DConfigBean;
 import javax.enterprise.deploy.spi.exceptions.ConfigurationException;
 import org.apache.geronimo.deployment.plugin.DConfigBeanRootSupport;
 import org.apache.geronimo.xbeans.geronimo.GerConnectorDocument;
+import org.apache.geronimo.xbeans.geronimo.GerAdminobjectInstanceType;
+import org.apache.geronimo.xbeans.geronimo.GerConnectiondefinitionInstanceType;
+import org.apache.geronimo.xbeans.geronimo.GerResourceadapterInstanceType;
+import org.apache.geronimo.xbeans.geronimo.GerConfigPropertySettingType;
 import org.apache.xmlbeans.XmlObject;
 import org.apache.xmlbeans.XmlException;
 import org.apache.xmlbeans.SchemaTypeLoader;
 import org.apache.xmlbeans.XmlBeans;
+import org.apache.xmlbeans.XmlCursor;
 
 /**
  * Represents "/" in a Geronimo Connector deployment plan (geronimo-ra.xml).
@@ -95,5 +107,60 @@
 
     protected SchemaTypeLoader getSchemaTypeLoader() {
         return SCHEMA_TYPE_LOADER;
+    }
+
+    /**
+     * When loaded, reset the cached "connector" child
+     */
+    public void fromXML(InputStream inputStream) throws XmlException, IOException {
+        DDBean ddb = connector.getDDBean();
+        super.fromXML(inputStream);
+        if(getConnectorDocument().getConnector() != null) {
+            connector = new ConnectorDCB(ddb, getConnectorDocument().getConnector());
+        } else {
+            connector = new ConnectorDCB(ddb, getConnectorDocument().addNewConnector());
+        }
+        //todo: fire some kind of notification for the DDBeans to catch?
+    }
+
+    /**
+     * A little trickery -- on a save event, temporarily remove any config-property-setting
+     * elements with a null value, and then immediately replace them again.  This is because
+     * we don't want to write them out as null, but we also want to keep the objects in
+     * sync 1:1 with the config params declared in the J2EE deployment descriptor.
+     */
+    public void toXML(OutputStream outputStream) throws IOException {
+        List parents = new ArrayList();
+        clearNulls(parents);
+        try {
+            super.toXML(outputStream);
+        } finally {
+            for (int i = 0; i < parents.size(); i++) {
+                Object parent = parents.get(i);
+                if(parent instanceof ConnectionDefinitionInstance) {
+                    ConnectionDefinitionInstance instance = (ConnectionDefinitionInstance) parent;
+                    instance.reconfigure();
+                } //todo: else if instanceof ResourceAdapterInstance, else if instanceof AdminObjectInstance
+            }
+        }
+    }
+
+    private void clearNulls(List parents) {
+        ResourceAdapter[] adapters = connector.getResourceAdapter();
+        for (int i = 0; i < adapters.length; i++) {
+            ResourceAdapter adapter = adapters[i];
+            // todo: check resource adapter instances
+            ConnectionDefinition defs[] = adapter.getConnectionDefinition();
+            for (int j = 0; j < defs.length; j++) {
+                ConnectionDefinition def = defs[j];
+                ConnectionDefinitionInstance instances[] = def.getConnectionInstances();
+                for (int k = 0; k < instances.length; k++) {
+                    ConnectionDefinitionInstance instance = instances[k];
+                    parents.add(instance);
+                    instance.clearNullSettings();
+                }
+            }
+        }
+        //todo: check admin object instances
     }
 }

Modified: geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ConnectorDCB.java
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ConnectorDCB.java?rev=357484&r1=357483&r2=357484&view=diff
==============================================================================
--- geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ConnectorDCB.java (original)
+++ geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ConnectorDCB.java Sun Dec 18 10:04:45 2005
@@ -47,7 +47,6 @@
         }
         //todo: do something if resourceAdapterDDBean is null
         loadExistingData(connector);
-        //todo: load defaults from J2EE DD /connector/resourceadapter
 
         // Make sure we're told if /connector/resourceadapter is replaced!
         connectorDDBean.addXpathListener("resourceadapter", new XpathListener() {
@@ -256,6 +255,8 @@
 
 
     // ----------------------- End of JavaBean Properties ----------------------
+
+    
 
     protected SchemaTypeLoader getSchemaTypeLoader() {
         return Connector15DCBRoot.SCHEMA_TYPE_LOADER;

Modified: geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ResourceAdapter.java
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ResourceAdapter.java?rev=357484&r1=357483&r2=357484&view=diff
==============================================================================
--- geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ResourceAdapter.java (original)
+++ geronimo/branches/1.0/modules/connector-builder/src/java/org/apache/geronimo/connector/deployment/jsr88/ResourceAdapter.java Sun Dec 18 10:04:45 2005
@@ -27,7 +27,9 @@
 import org.apache.xmlbeans.SchemaTypeLoader;
 
 /**
- * Represents /connector/resourceadapter in the Geronimo Connector deployment plan
+ * Represents /connector/resourceadapter in the Geronimo Connector deployment plan.
+ * Note: is not a DConfigBean, because there may be more than one ResourceAdapter
+ * in the Geronimo plan per ResourceAdapter in the J2EE deployment descriptor.
  *
  * @version $Rev$ $Date$
  */
@@ -51,7 +53,6 @@
     void configure(DDBean resourceAdapter, GerResourceadapterType ra) {
         this.resourceAdapter = resourceAdapter;
         setXmlObject(ra);
-        //todo: configure myself from the ra
         if(ra.isSetOutboundResourceadapter()) {
             DDBean[] test = resourceAdapter.getChildBean("outbound-resourceadapter");
             if(test != null && test.length > 0) {

Added: geronimo/branches/1.0/modules/connector-builder/src/test-resources/plan-with-nulls.xml
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.0/modules/connector-builder/src/test-resources/plan-with-nulls.xml?rev=357484&view=auto
==============================================================================
--- geronimo/branches/1.0/modules/connector-builder/src/test-resources/plan-with-nulls.xml (added)
+++ geronimo/branches/1.0/modules/connector-builder/src/test-resources/plan-with-nulls.xml Sun Dec 18 10:04:45 2005
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<connector configId="user/database-pool-TestPool/1/car" xmlns="http://geronimo.apache.org/xml/ns/j2ee/connector-1.0">
+    <dep:dependency xmlns:dep="http://geronimo.apache.org/xml/ns/deployment-1.0">
+        <dep:uri>org.apache.derby/derbyclient/10.1.1.0/jar</dep:uri>
+    </dep:dependency>
+    <resourceadapter>
+        <outbound-resourceadapter>
+            <connection-definition>
+                <connectionfactory-interface>javax.sql.DataSource</connectionfactory-interface>
+                <connectiondefinition-instance>
+                    <name>TestPool</name>
+<!--
+                    <config-property-setting name="Password" xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
+-->
+                    <config-property-setting name="CommitBeforeAutocommit">false</config-property-setting>
+                    <config-property-setting name="Driver">org.apache.derby.jdbc.EmbeddedDriver</config-property-setting>
+                    <config-property-setting name="ExceptionSorterClass">org.tranql.connector.AllExceptionsAreFatalSorter</config-property-setting>
+<!--
+                    <config-property-setting name="UserName" xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
+-->
+                    <config-property-setting name="ConnectionURL">jdbc:derby:TestDatabase;create=true</config-property-setting>
+                    <connectionmanager>
+                        <local-transaction/>
+                        <single-pool>
+                            <match-one/>
+                        </single-pool>
+                    </connectionmanager>
+                </connectiondefinition-instance>
+            </connection-definition>
+        </outbound-resourceadapter>
+    </resourceadapter>
+</connector>

Propchange: geronimo/branches/1.0/modules/connector-builder/src/test-resources/plan-with-nulls.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: geronimo/branches/1.0/modules/connector-builder/src/test/org/apache/geronimo/connector/deployment/jsr88/Connector15DCBTest.java
URL: http://svn.apache.org/viewcvs/geronimo/branches/1.0/modules/connector-builder/src/test/org/apache/geronimo/connector/deployment/jsr88/Connector15DCBTest.java?rev=357484&r1=357483&r2=357484&view=diff
==============================================================================
--- geronimo/branches/1.0/modules/connector-builder/src/test/org/apache/geronimo/connector/deployment/jsr88/Connector15DCBTest.java (original)
+++ geronimo/branches/1.0/modules/connector-builder/src/test/org/apache/geronimo/connector/deployment/jsr88/Connector15DCBTest.java Sun Dec 18 10:04:45 2005
@@ -16,14 +16,21 @@
  */
 package org.apache.geronimo.connector.deployment.jsr88;
 
-import java.net.URL;
-import java.util.Set;
-import java.util.HashSet;
-import java.util.Collections;
-import javax.enterprise.deploy.shared.ModuleType;
-import javax.enterprise.deploy.model.DDBeanRoot;
 import junit.framework.TestCase;
+import org.apache.geronimo.connector.deployment.RARConfiguration;
 import org.apache.geronimo.deployment.tools.loader.ConnectorDeployable;
+import org.apache.geronimo.xbeans.geronimo.GerConnectorDocument;
+import org.apache.geronimo.xbeans.geronimo.GerConfigPropertySettingType;
+
+import javax.enterprise.deploy.model.DDBeanRoot;
+import javax.enterprise.deploy.shared.ModuleType;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
 
 /**
  * @version $Rev$ $Date$
@@ -105,19 +112,19 @@
         for (int i = 0; i < 6; i++) {
             ConfigPropertySetting setting = instance.getConfigPropertySetting(i);
             if(setting.getName().equals("Driver")) {
-                assertEquals("", setting.getValue());
+                assertNull(setting.getValue());
                 setting.setValue("org.postgresql.Driver");
                 ++found;
             } else if(setting.getName().equals("ConnectionURL")) {
-                assertEquals("", setting.getValue());
+                assertNull(setting.getValue());
                 setting.setValue("jdbc:postgresql://localhost/TestDatabase");
                 ++found;
             } else if(setting.getName().equals("UserName")) {
-                assertEquals("", setting.getValue());
+                assertNull(setting.getValue());
                 setting.setValue("dbuser");
                 ++found;
             } else if(setting.getName().equals("Password")) {
-                assertEquals("", setting.getValue());
+                assertNull(setting.getValue());
                 setting.setValue("dbpass");
                 ++found;
             } else {
@@ -150,7 +157,115 @@
         pool.setMaxSize(new Integer(30));
         pool.setBlockingTimeoutMillis(new Integer(5000));
         //todo: Look at the XmlBeans tree and make sure the right stuff is in there
-        System.out.println(dcbRoot.getConnectorDocument());
+//        System.out.println(dcbRoot.getConnectorDocument());
+    }
+
+    public void testWriteWithNulls() throws Exception {
+        InputStream in = classLoader.getResource("plan-with-nulls.xml").openStream();
+
+        // Create and test the DDBeanRoot
+        URL resource = classLoader.getResource("database.rar");
+        assertNotNull(resource);
+        ConnectorDeployable deployable = new ConnectorDeployable(resource);
+        assertEquals(ModuleType.RAR, deployable.getType());
+        DDBeanRoot root = deployable.getDDBeanRoot();
+        assertNotNull(root);
+        assertEquals(ModuleType.RAR, root.getType());
+        assertEquals(deployable, root.getDeployableObject());
+        // Create the DConfigBeanRoot
+        Connector15DCBRoot dcbRoot = new Connector15DCBRoot(root);
+        RARConfiguration configuration = new RARConfiguration(deployable, dcbRoot);
+        configuration.restore(in);
+        // Try the /connector element
+        ConnectorDCB connector = (ConnectorDCB) dcbRoot.getDConfigBean(root.getChildBean(dcbRoot.getXpaths()[0])[0]);
+        assertNotNull(connector);
+        // Try the /connector/resourceadapter element
+        assertNotNull(connector.getResourceAdapter());
+        assertEquals(1, connector.getResourceAdapter().length);
+        ResourceAdapter adapter = connector.getResourceAdapter()[0];
+        assertNotNull(adapter);
+        // Try the /connector/resourceadapter/outbound-resourceadapter/connection-definition element
+        assertNotNull(adapter.getConnectionDefinition());
+        assertEquals(1, adapter.getConnectionDefinition().length);
+        ConnectionDefinition definition = adapter.getConnectionDefinition(0);
+        // Try the .../connection-definition/connectiondefinition-instance elements
+        assertNotNull(definition.getConnectionInstances());
+        assertEquals(1, definition.getConnectionInstances().length);
+        ConnectionDefinitionInstance instance = definition.getConnectionInstances()[0];
+        // Try the .../connection-definition/connectiondefinition-instance/config-property-setting elements
+        assertNotNull(instance.getConfigPropertySetting());
+        assertEquals(6, instance.getConfigPropertySetting().length);
+        int nullCount = 0;
+        for (int i = 0; i < 6; i++) {
+            if(instance.getConfigPropertySetting(i).getValue() == null) {
+                ++nullCount;
+            } else if(instance.getConfigPropertySetting(i).getValue().equals("")) {
+                instance.getConfigPropertySetting()[i].setValue(null);
+                ++nullCount;
+            }
+        }
+        // Read the generated XML and count config property setting elements (should be 4)
+        assertEquals(2, nullCount);
+        ByteArrayOutputStream pout = new ByteArrayOutputStream();
+        dcbRoot.toXML(pout);
+        pout.close();
+        ByteArrayInputStream pin = new ByteArrayInputStream(pout.toByteArray());
+        GerConnectorDocument doc = GerConnectorDocument.Factory.parse(pin);
+        pin.close();
+        GerConfigPropertySettingType[] settings = doc.getConnector().getResourceadapterArray(0).
+                getOutboundResourceadapter().getConnectionDefinitionArray(0).
+                getConnectiondefinitionInstanceArray(0).getConfigPropertySettingArray();
+        assertEquals(4, settings.length);
+        for (int i = 0; i < settings.length; i++) {
+            GerConfigPropertySettingType setting = settings[i];
+            if(setting.getName().equals("CommitBeforeAutocommit")) {
+                assertEquals("false", setting.getStringValue());
+            } else if(setting.getName().equals("Driver")) {
+                assertEquals("org.apache.derby.jdbc.EmbeddedDriver", setting.getStringValue());
+            } else if(setting.getName().equals("ExceptionSorterClass")) {
+                assertEquals("org.tranql.connector.AllExceptionsAreFatalSorter", setting.getStringValue());
+            } else if(setting.getName().equals("ConnectionURL")) {
+                assertEquals("jdbc:derby:TestDatabase;create=true", setting.getStringValue());
+            } else fail("Unknown connection setting '"+setting.getName()+"'");
+        }
+        // Make sure the original objects didn't lose track of the null config settings
+        assertEquals(6, instance.getConfigPropertySetting().length);
+        // Now set them to blank
+        nullCount = 0;
+        for (int i = 0; i < 6; i++) {
+            if(instance.getConfigPropertySetting()[i].getValue() == null) {
+                instance.getConfigPropertySetting()[i].setValue("");
+                ++nullCount;
+            }
+        }
+        assertEquals(2, nullCount);
+        // Now make sure we write out with 6
+        pout = new ByteArrayOutputStream();
+        dcbRoot.toXML(pout);
+        pout.close();
+        pin = new ByteArrayInputStream(pout.toByteArray());
+        doc = GerConnectorDocument.Factory.parse(pin);
+        pin.close();
+        settings = doc.getConnector().getResourceadapterArray(0).
+                getOutboundResourceadapter().getConnectionDefinitionArray(0).
+                getConnectiondefinitionInstanceArray(0).getConfigPropertySettingArray();
+        assertEquals(6, settings.length);
+        for (int i = 0; i < settings.length; i++) {
+            GerConfigPropertySettingType setting = settings[i];
+            if(setting.getName().equals("UserName")) {
+                assertEquals("", setting.getStringValue());
+            } else if(setting.getName().equals("Password")) {
+                assertEquals("", setting.getStringValue());
+            } else if(setting.getName().equals("CommitBeforeAutocommit")) {
+                assertEquals("false", setting.getStringValue());
+            } else if(setting.getName().equals("Driver")) {
+                assertEquals("org.apache.derby.jdbc.EmbeddedDriver", setting.getStringValue());
+            } else if(setting.getName().equals("ExceptionSorterClass")) {
+                assertEquals("org.tranql.connector.AllExceptionsAreFatalSorter", setting.getStringValue());
+            } else if(setting.getName().equals("ConnectionURL")) {
+                assertEquals("jdbc:derby:TestDatabase;create=true", setting.getStringValue());
+            } else fail("Unknown connection setting '"+setting.getName()+"'");
+        }
     }
 
     protected void setUp() throws Exception {