You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by bi...@apache.org on 2007/10/26 04:06:48 UTC

svn commit: r588466 - in /incubator/cxf/trunk/rt/javascript/src: main/java/org/apache/cxf/javascript/ main/java/org/apache/cxf/javascript/types/ test/java/org/ test/java/org/apache/ test/java/org/apache/cxf/ test/java/org/apache/cxf/javascript/ test/ja...

Author: bimargulies
Date: Thu Oct 25 19:06:47 2007
New Revision: 588466

URL: http://svn.apache.org/viewvc?rev=588466&view=rev
Log:
More code for the javascript generator, and some trivial error handling code to replace 'printStackTrace' calls.

Added:
    incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/BasicNameManager.java
    incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/NameManager.java
    incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/types/Messages.properties
    incubator/cxf/trunk/rt/javascript/src/test/java/org/
    incubator/cxf/trunk/rt/javascript/src/test/java/org/apache/
    incubator/cxf/trunk/rt/javascript/src/test/java/org/apache/cxf/
    incubator/cxf/trunk/rt/javascript/src/test/java/org/apache/cxf/javascript/
    incubator/cxf/trunk/rt/javascript/src/test/java/org/apache/cxf/javascript/types/
    incubator/cxf/trunk/rt/javascript/src/test/java/org/apache/cxf/javascript/types/SerializationTests.java
    incubator/cxf/trunk/rt/javascript/src/test/resources/serializationTestBeans.xml
Modified:
    incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/JavascriptUtils.java
    incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/UnsupportedSchemaConstruct.java
    incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/types/SchemaJavascriptBuilder.java

Added: incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/BasicNameManager.java
URL: http://svn.apache.org/viewvc/incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/BasicNameManager.java?rev=588466&view=auto
==============================================================================
--- incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/BasicNameManager.java (added)
+++ incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/BasicNameManager.java Thu Oct 25 19:06:47 2007
@@ -0,0 +1,70 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.javascript;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.cxf.service.model.SchemaInfo;
+import org.apache.cxf.service.model.ServiceInfo;
+import org.apache.ws.commons.schema.XmlSchemaComplexType;
+import org.apache.ws.commons.schema.utils.NamespacePrefixList;
+
+/**
+ * 
+ */
+public class BasicNameManager implements NameManager {
+    
+    private Map<String, String> nsPrefixMap;
+    
+    public BasicNameManager(ServiceInfo service) {
+        nsPrefixMap = new HashMap<String, String>();
+        Set<String> poorPrefixURIs = new HashSet<String>();
+        for (SchemaInfo schemaInfo : service.getSchemas()) {
+            NamespacePrefixList schemaPrefixList = schemaInfo.getSchema().getNamespaceContext();
+            for (String declaredPrefix : schemaPrefixList.getDeclaredPrefixes()) {
+                String uri = schemaPrefixList.getNamespaceURI(declaredPrefix);
+                
+                if (!nsPrefixMap.containsKey(uri)) { // first schema to define a prefix wins.
+                    if (declaredPrefix.startsWith("ns") || "tns".equals(declaredPrefix)) {
+                        poorPrefixURIs.add(uri);
+                    } else { 
+                        nsPrefixMap.put(uri, declaredPrefix.toUpperCase());
+                    }
+                }
+            }
+        }
+        
+        for (String uri : poorPrefixURIs) {
+            // this needs more work later. We are bound to annoy someone somehow in this area.
+            String jsPrefix = uri.replace("http:", "").replace("uri:", "").replaceAll("[\\.:/-]", "_");
+            nsPrefixMap.put(uri, jsPrefix.toUpperCase());
+        }
+    }
+
+    /** {@inheritDoc}*/
+    public String getJavascriptName(XmlSchemaComplexType schemaType) {
+        return nsPrefixMap.get(schemaType.getQName().getNamespaceURI()) 
+        //TODO: the local part of the name may be a problem for JavaScript.
+                               + schemaType.getQName().getLocalPart();
+    }
+}

Modified: incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/JavascriptUtils.java
URL: http://svn.apache.org/viewvc/incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/JavascriptUtils.java?rev=588466&r1=588465&r2=588466&view=diff
==============================================================================
--- incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/JavascriptUtils.java (original)
+++ incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/JavascriptUtils.java Thu Oct 25 19:06:47 2007
@@ -19,8 +19,14 @@
 
 package org.apache.cxf.javascript;
 
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 import java.util.Stack;
 
+import org.apache.ws.commons.schema.XmlSchemaSimpleType;
+
 /**
  * 
  */
@@ -29,11 +35,41 @@
     private StringBuffer code;
     private Stack<String> prefixStack;
     private String xmlStringAccumulatorVariable;
+    private Map<String, String> defaultValueForSimpleType;
+    private Set<String> nonStringSimpleTypes;
     
     public JavascriptUtils(StringBuffer code) {
         this.code = code;
+        defaultValueForSimpleType = new HashMap<String, String>();
+        defaultValueForSimpleType.put("int", "0");
+        defaultValueForSimpleType.put("long", "0");
+        defaultValueForSimpleType.put("float", "0.0");
+        defaultValueForSimpleType.put("double", "0.0");
+        nonStringSimpleTypes = new HashSet<String>();
+        nonStringSimpleTypes.add("int");
+        nonStringSimpleTypes.add("long");
+        nonStringSimpleTypes.add("float");
+        nonStringSimpleTypes.add("double");
+        
         prefixStack = new Stack<String>();
-        prefixStack.push("");
+        prefixStack.push("    ");
+    }
+    
+    public String getDefaultValueForSimpleType(XmlSchemaSimpleType type) {
+        String val = defaultValueForSimpleType.get(type.getName());
+        if (val == null) {
+            return "''";
+        } else {
+            return val;
+        }
+    }
+    
+    public boolean isStringSimpleType(XmlSchemaSimpleType type) {
+        return !nonStringSimpleTypes.contains(type.getName());
+    }
+    
+    public void setXmlStringAccumulator(String variableName) {
+        xmlStringAccumulatorVariable = variableName;
     }
     
     public void startXmlStringAccumulator(String variableName) {
@@ -48,11 +84,22 @@
         return value.replaceAll("'", "\\'");
     }
     
+    public String escapeStringQuotes(String data) {
+        return data.replace("'", "\\'");
+    }
+    
     /**
      * emit javascript to append a value to the accumulator. 
      * @param value
      */
-    public void appendAppend(String value) {
+    public void appendString(String value) {
+        code.append(prefix());
+        code.append(xmlStringAccumulatorVariable + " = " + xmlStringAccumulatorVariable + " + '");
+        code.append(escapeStringQuotes(value));
+        code.append("';" + NL);
+    }
+    
+    public void appendExpression(String value) {
         code.append(prefix());
         code.append(xmlStringAccumulatorVariable + " = " + xmlStringAccumulatorVariable + " + ");
         code.append(value);

Added: incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/NameManager.java
URL: http://svn.apache.org/viewvc/incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/NameManager.java?rev=588466&view=auto
==============================================================================
--- incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/NameManager.java (added)
+++ incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/NameManager.java Thu Oct 25 19:06:47 2007
@@ -0,0 +1,26 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.javascript;
+
+import org.apache.ws.commons.schema.XmlSchemaComplexType;
+
+public interface NameManager {
+    String getJavascriptName(XmlSchemaComplexType schemaType);
+}

Modified: incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/UnsupportedSchemaConstruct.java
URL: http://svn.apache.org/viewvc/incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/UnsupportedSchemaConstruct.java?rev=588466&r1=588465&r2=588466&view=diff
==============================================================================
--- incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/UnsupportedSchemaConstruct.java (original)
+++ incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/UnsupportedSchemaConstruct.java Thu Oct 25 19:06:47 2007
@@ -18,6 +18,8 @@
  */
 package org.apache.cxf.javascript;
 
+import org.apache.cxf.common.i18n.Message;
+
 /**
  * This exception is thrown when the Javascript client generator hits a schema
  * construct that it cannot handle. 
@@ -37,6 +39,10 @@
 
     public UnsupportedSchemaConstruct(String explanation, Throwable cause) {
         super(explanation, cause);
+    }
+
+    public UnsupportedSchemaConstruct(Message message) {
+        super(message.toString());
     }
 
 }

Added: incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/types/Messages.properties
URL: http://svn.apache.org/viewvc/incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/types/Messages.properties?rev=588466&view=auto
==============================================================================
--- incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/types/Messages.properties (added)
+++ incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/types/Messages.properties Thu Oct 25 19:06:47 2007
@@ -0,0 +1,24 @@
+#
+#
+#    Licensed to the Apache Software Foundation (ASF) under one
+#    or more contributor license agreements. See the NOTICE file
+#    distributed with this work for additional information
+#    regarding copyright ownership. The ASF licenses this file
+#    to you under the Apache License, Version 2.0 (the
+#    "License"); you may not use this file except in compliance
+#    with the License. You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing,
+#    software distributed under the License is distributed on an
+#    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#    KIND, either express or implied. See the License for the
+#    specific language governing permissions and limitations
+#    under the License.
+#
+#
+NON_ELEMENT_CHILD=JavaScript limitation: Non-Element sequence member {0} of {1}. {2}
+NON_SEQUENCE_PARTICLE=JavaScript limitation: Type {0} is not defined as a sequence. {1}
+ABSTRACT_ELEMENT=JavaScript limitation: Abstract element {0} of {1}. {2}
+NULL_PARTICLE=JavaScript limitation: Type {0} has no particle. {1} 

Modified: incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/types/SchemaJavascriptBuilder.java
URL: http://svn.apache.org/viewvc/incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/types/SchemaJavascriptBuilder.java?rev=588466&r1=588465&r2=588466&view=diff
==============================================================================
--- incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/types/SchemaJavascriptBuilder.java (original)
+++ incubator/cxf/trunk/rt/javascript/src/main/java/org/apache/cxf/javascript/types/SchemaJavascriptBuilder.java Thu Oct 25 19:06:47 2007
@@ -19,17 +19,30 @@
 
 package org.apache.cxf.javascript.types;
 
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Logger;
+
 import javax.xml.namespace.QName;
 
+import org.apache.cxf.common.i18n.Message;
+import org.apache.cxf.common.logging.LogUtils;
 import org.apache.cxf.javascript.JavascriptUtils;
+import org.apache.cxf.javascript.NameManager;
 import org.apache.cxf.javascript.UnsupportedSchemaConstruct;
 import org.apache.cxf.service.model.SchemaInfo;
 import org.apache.cxf.wsdl.WSDLConstants;
 import org.apache.ws.commons.schema.XmlSchemaComplexType;
 import org.apache.ws.commons.schema.XmlSchemaElement;
 import org.apache.ws.commons.schema.XmlSchemaForm;
+import org.apache.ws.commons.schema.XmlSchemaObject;
+import org.apache.ws.commons.schema.XmlSchemaObjectTable;
 import org.apache.ws.commons.schema.XmlSchemaParticle;
 import org.apache.ws.commons.schema.XmlSchemaSequence;
+import org.apache.ws.commons.schema.XmlSchemaSimpleType;
 import org.apache.ws.commons.schema.XmlSchemaType;
 
 /**
@@ -38,15 +51,71 @@
  * @author bimargulies
  */
 public class SchemaJavascriptBuilder {
+    
+    private static final Logger LOG = LogUtils.getL7dLogger(SchemaJavascriptBuilder.class);
+    
     private static final XmlSchemaForm QUALIFIED = new XmlSchemaForm(XmlSchemaForm.QUALIFIED);
+    private static final XmlSchemaForm UNQUALIFIED = new XmlSchemaForm(XmlSchemaForm.UNQUALIFIED);
+    
     private static final String XSI_NS_ATTR = WSDLConstants.NP_XMLNS + ":" 
-        + WSDLConstants.NP_SCHEMA_XSI + "=" + WSDLConstants.NU_SCHEMA_XSI;
+        + WSDLConstants.NP_SCHEMA_XSI + "='" + WSDLConstants.NU_SCHEMA_XSI + "'";
     private static final String NIL_ATTRIBUTES = XSI_NS_ATTR + " xsi:nil='true'";
     // The schema that we are operating upon.
     private SchemaInfo schemaInfo;
+    private NameManager nameManager;
+    private Map<String, String> fallbackNamespacePrefixMap;
+    private int nsCounter;
     
-    public SchemaJavascriptBuilder(SchemaInfo schemaInfo) {
+    public SchemaJavascriptBuilder(NameManager nameManager, SchemaInfo schemaInfo) {
+        this.nameManager = nameManager;
         this.schemaInfo = schemaInfo;
+        fallbackNamespacePrefixMap = new HashMap<String, String>();
+    }
+    
+    // this class assumes that the rest of the code is not going to try to use the same prefix twice
+    // for two different URIs.
+    private static class NamespacePrefixAccumulator {
+        private StringBuffer attributes;
+        private Set<String> prefixes;
+        
+        NamespacePrefixAccumulator() {
+            attributes = new StringBuffer();
+            prefixes = new HashSet<String>();
+        }
+        
+        void collect(String prefix, String uri) {
+            if (!prefixes.contains(prefix)) {
+                attributes.append("xmlns:" + prefix + "='" + uri + "' ");
+                prefixes.add(prefix);
+            }
+        }
+        
+        String getAttributes() {
+            return attributes.toString();
+        }
+    }
+    
+    private String cleanedUpSchemaSource(XmlSchemaType subject) {
+        if (subject.getSourceURI() == null) {
+            return "";
+        } else {
+            return subject.getSourceURI() + ":" + subject.getLineNumber(); 
+        }
+    }
+    
+    private void unsupportedConstruct(String messageKey, XmlSchemaType subject) {
+        Message message = new Message(messageKey, LOG, subject.getQName(), 
+                                      cleanedUpSchemaSource(subject));
+        throw new UnsupportedSchemaConstruct(message);
+        
+    }
+    
+    private void unsupportedConstruct(String messageKey, String what, XmlSchemaType subject) {
+        Message message = new Message(messageKey, LOG, what, subject.getQName(), 
+                                      cleanedUpSchemaSource(subject));
+        LOG.severe(message.toString());
+        throw new UnsupportedSchemaConstruct(message);
+        
     }
     
     public static boolean isParticleArray(XmlSchemaParticle particle) {
@@ -57,22 +126,187 @@
         return particle.getMinOccurs() == 0 && particle.getMaxOccurs() == 1;
     }
     
-    private String xmlElementString(XmlSchemaElement element) {
-        return getQNameString(element.getQName());
+    /**
+     * This function obtains a name, perhaps namespace-qualified, for an element.
+     * It also maintains a Map that records all the prefixes used in the course
+     * of working on a single serializer function (and thus a single complex-type-element
+     * XML element) which is used for namespace prefix management.
+     * @param element
+     * @param namespaceMap
+     * @return
+     */
+    private String xmlElementString(XmlSchemaElement element, NamespacePrefixAccumulator accumulator) {
+        QName qname = element.getQName();
+        if (isElementNameQualified(element)) {
+            String prefix = qname.getPrefix();
+            if ("".equals(prefix)) { // this is not quite good enough.
+                prefix = getPrefix(qname.getNamespaceURI());
+            }
+            accumulator.collect(prefix, qname.getNamespaceURI());
+            return prefix + ":" + qname.getLocalPart();
+        } else {
+            return qname.getLocalPart();
+        }
     }
     
-    private String getQNameString(QName name) {
-        if (schemaInfo.getSchema().getElementFormDefault().equals(QUALIFIED)) {
-            return getPrefix(name.getNamespaceURI()) + ":" + name.getLocalPart();
-        } else {
-            return name.getLocalPart();
+    private boolean isElementNameQualified(XmlSchemaElement element) {
+        if (element.getForm().equals(QUALIFIED)) {
+            return true;
+        }
+        if (element.getForm().equals(UNQUALIFIED)) {
+            return false;
+        }
+        return schemaInfo.getSchema().getElementFormDefault().equals(QUALIFIED);
+    }
+    
+    private String getPrefix(String namespaceURI) {
+        String schemaPrefix = schemaInfo.getSchema().getNamespaceContext().getPrefix(namespaceURI);
+        if (schemaPrefix == null || "tns".equals(schemaPrefix)) {
+            schemaPrefix = fallbackNamespacePrefixMap.get(namespaceURI);
+            if (schemaPrefix == null) {
+                schemaPrefix = "jns" + nsCounter;
+                nsCounter++;
+                fallbackNamespacePrefixMap.put(namespaceURI, schemaPrefix);
+            }
         }
+        return schemaPrefix;
+    }
+    
+    public String generateCodeForSchema(SchemaInfo schema) {
+        StringBuffer code = new StringBuffer();
 
+        XmlSchemaObjectTable schemaTypes = schema.getSchema().getSchemaTypes();
+        Iterator namesIterator = schemaTypes.getNames();
+        while (namesIterator.hasNext()) {
+            QName name = (QName)namesIterator.next();
+            XmlSchemaObject xmlSchemaObject = (XmlSchemaObject)schemaTypes.getItem(name);
+            if (xmlSchemaObject instanceof XmlSchemaComplexType) {
+                try {
+                    XmlSchemaComplexType complexType = (XmlSchemaComplexType)xmlSchemaObject;
+                    code.append(complexTypeConstructorAndAccessors(complexType));
+                    code.append(complexTypeSerializerFunction(complexType));
+                } catch (UnsupportedSchemaConstruct usc) {
+                    continue; // it could be empty, but the style checker would complain.
+                }
+            }
+        }
+        
+        return code.toString();
     }
+    
+    public String complexTypeConstructorAndAccessors(XmlSchemaComplexType type) {
+        StringBuffer code = new StringBuffer();
+        StringBuffer accessors = new StringBuffer();
+        JavascriptUtils utils = new JavascriptUtils(code);
+        XmlSchemaParticle particle = type.getParticle();
+        XmlSchemaSequence sequence = null;
+        final String elementPrefix = "this._";
+        
+        String typeObjectName = nameManager.getJavascriptName(type);
+        code.append(typeObjectName + " () {\n");
+        
+        if (particle == null) {
+            unsupportedConstruct("NULL_PARTICLE", type);
+        }
+        
+        try {
+            sequence = (XmlSchemaSequence) particle;
+        } catch (ClassCastException cce) {
+            unsupportedConstruct("NON_SEQUENCE_PARTICLE", type);
+        }
+        
+        for (int i = 0; i < sequence.getItems().getCount(); i++) {
+            XmlSchemaObject thing = sequence.getItems().getItem(i);
+            if (!(thing instanceof XmlSchemaElement)) {
+                unsupportedConstruct("NON_ELEMENT_CHILD", thing.getClass().getSimpleName(), type);
+            }
+            
+            XmlSchemaElement elChild = (XmlSchemaElement)thing;
+            XmlSchemaType elType = elChild.getSchemaType();
+            boolean nillable = elChild.isNillable();
+            if (elChild.isAbstract()) { 
+                unsupportedConstruct("ABSTRACT_ELEMENT", elChild.getName(), type);
+            }
+            
+            // Assume that no lunatic has created multiple elements that differ only by namespace.
+            // if elementForm is unqualified, how can that be valid?
+            String elementName = elementPrefix + elChild.getName();
+
+            String accessorName = typeObjectName + "_get" + elChild.getName();
+            accessors.append(accessorName + "() { return " + elementName + ";}\n");
+            accessors.append(typeObjectName + ".get" + elChild.getName() + " = " + accessorName + ";\n");
+            
+            accessorName = typeObjectName + "_set" + elChild.getName();
+            accessors.append(accessorName + "(value) {" + elementName + " = value;}\n");
+            accessors.append(typeObjectName + ".set" + elChild.getName() + " = " + accessorName + ";\n");
+            
+            if (isParticleOptional(elChild) || (nillable && !isParticleArray(elChild))) {
+                utils.appendLine(elementName + " = null;");
+            } else if (isParticleArray(elChild)) {
+                utils.appendLine(elementName + " = [];");
+            } else if (elType instanceof XmlSchemaComplexType) {
+                // even for required complex elements, we leave them null. 
+                // otherwise, we could end up in a cycle or otherwise miserable. The 
+                // application code is responsible for this.
+                utils.appendLine(elementName + " = null;");
+            } else {
+                String defaultValueString = elChild.getDefaultValue();
+                if (defaultValueString == null) {
+                    defaultValueString = 
+                        utils.getDefaultValueForSimpleType((XmlSchemaSimpleType)elChild.getSchemaType());
+                }
+                utils.appendLine(elementName + " = " + defaultValueString + ";");
+            }
+        }
+        code.append("}\n");
+        return code.toString() + "\n" + accessors.toString();
+    }
+    
+    /**
+     * Produce a serializer function for a type.
+     * These functions emit the surrounding element XML if the caller supplies an XML element name.
+     * It's not quite as simple as that, though. The element name may need namespace qualification,
+     * and this function will add more namespace prefixes as needed.
+     * @param type
+     * @return
+     */
+    public String complexTypeSerializerFunction(XmlSchemaComplexType type) {
+        
+        StringBuffer bodyCode = new StringBuffer();
+        JavascriptUtils bodyUtils = new JavascriptUtils(bodyCode);
+        bodyUtils.setXmlStringAccumulator("xml");
+
+        NamespacePrefixAccumulator prefixAccumulator = new NamespacePrefixAccumulator();
+        complexTypeSerializerBody(type, "this._", bodyUtils, prefixAccumulator);
+        
+        StringBuffer code = new StringBuffer();
+        JavascriptUtils utils = new JavascriptUtils(code);
+        String functionName = nameManager.getJavascriptName(type) + "_" + "serialize";
+        code.append(functionName + "(elementName) {\n");
+        utils.startXmlStringAccumulator("xml");
+        utils.startIf("elementName != null");
+        utils.appendString("<");
+        utils.appendExpression("elementName");
+        // now add any accumulated namespaces.
+        String moreNamespaces = prefixAccumulator.getAttributes();
+        if (moreNamespaces.length() > 0) {
+            utils.appendString(" ");
+            utils.appendString(moreNamespaces);
+        }
+        utils.appendString(">");
+        utils.endBlock();
+        code.append(bodyCode);
+        utils.startIf("elementName != null");
+        utils.appendString("</");
+        utils.appendExpression("elementName");
+        utils.appendString(">");
+        utils.endBlock();
+        code.append("}\n");
 
-    private String getPrefix(String string) {
-        return schemaInfo.getSchema().getNamespaceContext().getPrefix(string);
+        code.append(nameManager.getJavascriptName(type) + ".serialize = " + functionName + ";\n");
+        return code.toString();
     }
+   
 
     /**
      * Build the serialization code for a complex type. At the top level, this operates on single items,
@@ -80,35 +314,31 @@
      * it manages optional elements and arrays.
      * @param type
      * @param elementPrefix
+     * @param bodyNamespaceURIs 
      * @return
      */
-    public void complexTypeSerializerBody(XmlSchemaComplexType type, 
+    protected void complexTypeSerializerBody(XmlSchemaComplexType type, 
                                           String elementPrefix, 
-                                          StringBuffer code) {
-        JavascriptUtils utils = new JavascriptUtils(code);
+                                          JavascriptUtils utils, 
+                                          NamespacePrefixAccumulator prefixAccumulator) {
+
         XmlSchemaParticle particle = type.getParticle();
         XmlSchemaSequence sequence = null;
-        try {
-            sequence = (XmlSchemaSequence) particle;
-        } catch (ClassCastException cce) {
-            throw new UnsupportedSchemaConstruct("Cannot build serializer for " + particle.toString());
-        }
-        
-        utils.startXmlStringAccumulator("xml");
+        sequence = (XmlSchemaSequence) particle;
 
         // XML Schema, please meet Iterable (not).
         for (int i = 0; i < sequence.getItems().getCount(); i++) {
             XmlSchemaElement elChild = (XmlSchemaElement)sequence.getItems().getItem(i);
             XmlSchemaType elType = elChild.getSchemaType();
             boolean nillable = elChild.isNillable();
-            if (elChild.isAbstract()) { 
-                throw new UnsupportedSchemaConstruct("Abstract element " + elChild.toString());
+            if (elChild.isAbstract()) {
+                unsupportedConstruct("ABSTRACT_ELEMENT", elChild.getName(), type);
             }
             
             // assume that no lunatic has created multiple elements that differ only by namespace.
             // or, perhaps, detect that when generating the parser?
             String elementName = elementPrefix + elChild.getName();
-            String elementXmlRef = xmlElementString(elChild);
+            String elementXmlRef = xmlElementString(elChild, prefixAccumulator);
             
             // first question: optional?
             if (isParticleOptional(elChild)) {
@@ -119,7 +349,7 @@
             // and nillable in the array case applies to the elements.
             if (nillable && !isParticleArray(elChild)) {
                 utils.startIf(elementName + " == null");
-                utils.appendAppend("<" + elementXmlRef + " " + NIL_ATTRIBUTES + "/>");
+                utils.appendString("<" + elementXmlRef + " " + NIL_ATTRIBUTES + "/>");
                 utils.appendElse();
             }
             
@@ -129,20 +359,24 @@
                 // we need an extra level of 'nil' testing here. Or do we, depending on the type structure?
                 // Recode and fiddle appropriately.
                 utils.startIf(elementName + " == null");
-                utils.appendAppend("<" + elementXmlRef + " " + NIL_ATTRIBUTES + "/>");
+                utils.appendString("<" + elementXmlRef + " " + NIL_ATTRIBUTES + "/>");
                 utils.appendElse();
             }
             
             // now for the thing itself.
-            utils.appendAppend("<" + elementXmlRef + ">");
             if (elType instanceof XmlSchemaComplexType) {
-                utils.appendAppend(elementName + ".serialize()");
+                utils.appendExpression(elementName + ".serialize(" + elementXmlRef + ")");
             } else {
+                utils.appendString("<" + elementXmlRef + ">");
                 // warning: this assumes that ordinary Javascript serialization is all we need.
                 // except for &gt; ad all of that.
-                utils.appendAppend("cxf_xml_serialize_string(" + elementName + ")");
+                if (utils.isStringSimpleType((XmlSchemaSimpleType)elType)) {
+                    utils.appendExpression("cxf_xml_serialize_string(" + elementName + ")");
+                } else {
+                    utils.appendExpression(elementName);
+                }
+                utils.appendString("</" + elementXmlRef + ">");
             }
-            utils.appendAppend("</" + elementXmlRef + ">");
             
             if (isParticleArray(elChild)) {
                 utils.endBlock(); // for the extra level of nil checking, which might be wrong.

Added: incubator/cxf/trunk/rt/javascript/src/test/java/org/apache/cxf/javascript/types/SerializationTests.java
URL: http://svn.apache.org/viewvc/incubator/cxf/trunk/rt/javascript/src/test/java/org/apache/cxf/javascript/types/SerializationTests.java?rev=588466&view=auto
==============================================================================
--- incubator/cxf/trunk/rt/javascript/src/test/java/org/apache/cxf/javascript/types/SerializationTests.java (added)
+++ incubator/cxf/trunk/rt/javascript/src/test/java/org/apache/cxf/javascript/types/SerializationTests.java Thu Oct 25 19:06:47 2007
@@ -0,0 +1,73 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.cxf.javascript.types;
+
+import java.util.Collection;
+import java.util.List;
+
+import javax.xml.namespace.QName;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.endpoint.Server;
+import org.apache.cxf.javascript.BasicNameManager;
+import org.apache.cxf.javascript.NameManager;
+import org.apache.cxf.service.Service;
+import org.apache.cxf.service.model.SchemaInfo;
+import org.apache.cxf.service.model.ServiceInfo;
+import org.apache.cxf.test.TestUtilities;
+import org.junit.Test;
+import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
+
+public class SerializationTests extends AbstractDependencyInjectionSpringContextTests {
+    private TestUtilities testUtilities;
+
+    public SerializationTests() {
+        testUtilities = new TestUtilities(getClass());
+    }
+
+    @Override
+    protected String[] getConfigLocations() {
+        return new String[] {"classpath:serializationTestBeans.xml"};
+    }
+    
+    @Test
+    public void testSerialization() throws Exception {
+        testUtilities.setBus((Bus)applicationContext.getBean("cxf"));
+        testUtilities.addDefaultNamespaces();
+        Server server = testUtilities.getServerForService(new QName("http://apache.org/type_test/doc", 
+                                                                "TypeTestPortTypeService"));
+        Service service = server.getEndpoint().getService();
+        List<ServiceInfo> serviceInfos = service.getServiceInfos();
+        // there can only be one.
+        assertEquals(1, serviceInfos.size());
+        ServiceInfo serviceInfo = serviceInfos.get(0);
+        Collection<SchemaInfo> schemata = serviceInfo.getSchemas();
+        NameManager nameManager = new BasicNameManager(serviceInfo);
+
+        for (SchemaInfo schema : schemata) {
+            SchemaJavascriptBuilder builder = new SchemaJavascriptBuilder(nameManager, schema);
+            String allThatJavascript = builder.generateCodeForSchema(schema);
+            assertNotNull(allThatJavascript);
+        }
+    }
+    
+    
+    
+}

Added: incubator/cxf/trunk/rt/javascript/src/test/resources/serializationTestBeans.xml
URL: http://svn.apache.org/viewvc/incubator/cxf/trunk/rt/javascript/src/test/resources/serializationTestBeans.xml?rev=588466&view=auto
==============================================================================
--- incubator/cxf/trunk/rt/javascript/src/test/resources/serializationTestBeans.xml (added)
+++ incubator/cxf/trunk/rt/javascript/src/test/resources/serializationTestBeans.xml Thu Oct 25 19:06:47 2007
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xmlns:jaxws="http://cxf.apache.org/jaxws"
+	xmlns:http="http://cxf.apache.org/transports/http/configuration"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
+						http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
+						http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd">
+						
+	<!-- CXF -->
+	<import resource="classpath:META-INF/cxf/cxf.xml" />
+	<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
+	<import resource="classpath:META-INF/cxf/cxf-extension-jaxws.xml" />
+	<import resource="classpath:META-INF/cxf/cxf-extension-local.xml" />
+
+	<!-- Services. We use the JAXB test server which handles a lot of types. -->
+	<jaxws:server id="TestServer" 
+                   serviceClass="org.apache.type_test.doc.TypeTestPortType" 
+	               address="local://TestService">
+	</jaxws:server>
+</beans>
+