alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Apache CXF example source code file (ServiceJavascriptBuilder.java)

This example Apache CXF source code file (ServiceJavascriptBuilder.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Apache CXF tags/keywords

list, log, logging, messageinfo, messageinfo, override, override, particleinfo, qname, string, string, util, xmlschemacomplextype, xmlschemacomplextype, xmlschemaelement, xmlschemasequence, xmlschematype

The Apache CXF ServiceJavascriptBuilder.java source code

/**
 * 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.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;

import javax.xml.namespace.QName;

import org.apache.cxf.binding.soap.SoapBindingConstants;
import org.apache.cxf.binding.soap.SoapBindingFactory;
import org.apache.cxf.binding.soap.SoapVersion;
import org.apache.cxf.binding.soap.model.SoapBindingInfo;
import org.apache.cxf.common.WSDLConstants;
import org.apache.cxf.common.i18n.Message;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.common.util.StringUtils;
import org.apache.cxf.common.xmlschema.SchemaCollection;
import org.apache.cxf.common.xmlschema.XmlSchemaUtils;
import org.apache.cxf.javascript.JavascriptUtils;
import org.apache.cxf.javascript.NameManager;
import org.apache.cxf.javascript.NamespacePrefixAccumulator;
import org.apache.cxf.javascript.ParticleInfo;
import org.apache.cxf.javascript.UnsupportedConstruct;
import org.apache.cxf.service.ServiceModelVisitor;
import org.apache.cxf.service.model.BindingInfo;
import org.apache.cxf.service.model.EndpointInfo;
import org.apache.cxf.service.model.FaultInfo;
import org.apache.cxf.service.model.InterfaceInfo;
import org.apache.cxf.service.model.MessageInfo;
import org.apache.cxf.service.model.MessagePartInfo;
import org.apache.cxf.service.model.OperationInfo;
import org.apache.cxf.service.model.ServiceInfo;
import org.apache.cxf.transport.local.LocalTransportFactory;
import org.apache.ws.commons.schema.XmlSchema;
import org.apache.ws.commons.schema.XmlSchemaAny;
import org.apache.ws.commons.schema.XmlSchemaComplexType;
import org.apache.ws.commons.schema.XmlSchemaElement;
import org.apache.ws.commons.schema.XmlSchemaObject;
import org.apache.ws.commons.schema.XmlSchemaObjectCollection;
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;

/**
 * Class to construct the JavaScript corresponding to a service.
 */
public class ServiceJavascriptBuilder extends ServiceModelVisitor {
    private static final Logger LOG = LogUtils.getL7dLogger(ServiceJavascriptBuilder.class);

    private SoapBindingInfo soapBindingInfo;
    private JavascriptUtils utils;
    private NameManager nameManager;
    private StringBuilder code;
    private String currentInterfaceClassName;
    private OperationInfo currentOperation;
    private Set<OperationInfo> operationsWithNameConflicts;
    private Set<MessageInfo> inputMessagesWithNameConflicts;
    private Set<MessageInfo> outputMessagesWithNameConflicts;
    private SchemaCollection xmlSchemaCollection;
    // When generating from a tool or ?js, we know the endpoint addr and can build it into the javascript.
    private String endpointAddress;
    
    private boolean isWrapped;
    // facts about the wrapper when there is one.
    private MessagePartInfo inputWrapperPartInfo;
    private String inputWrapperClassName;
    private XmlSchemaElement inputWrapperElement;
    private XmlSchemaComplexType inputWrapperComplexType;

    private MessagePartInfo outputWrapperPartInfo;
    private XmlSchemaElement outputWrapperElement;
    private XmlSchemaComplexType outputWrapperComplexType;

    // Javascript parameter names for the input parameters,
    // derived from the parts.
    private List<String> inputParameterNames = new ArrayList();
    // when not wrapped, we use this to keep track of the bits.
    private List<ParticleInfo> unwrappedElementsAndNames;
    
    private NamespacePrefixAccumulator prefixAccumulator;
    private BindingInfo xmlBindingInfo;
    private Map<String, OperationInfo> localOperationsNameMap;
    private Map<String, MessageInfo> localInputMessagesNameMap;
    private Map<String, MessageInfo> localOutputMessagesNameMap;

    private String opFunctionPropertyName;
    private String opFunctionGlobalName;

    private boolean isInUnwrappedOperation;
    private boolean nonVoidOutput;
    private boolean isRPC;

    /**
     * Construct builder object.
     * @param serviceInfo CXF service model description of the service.
     * @param endpointAddress http:// URL for the service, or null if not known.
     * @param prefixAccumulator object that keeps track of prefixes through an entire WSDL.
     * @param nameManager object that generates names for JavaScript objects.
     */
    public ServiceJavascriptBuilder(ServiceInfo serviceInfo,
                                    String endpointAddress,
                                    NamespacePrefixAccumulator prefixAccumulator,
                                    NameManager nameManager) {
        super(serviceInfo);
        this.endpointAddress = endpointAddress;
        code = new StringBuilder();
        utils = new JavascriptUtils(code);
        this.nameManager = nameManager;
        xmlSchemaCollection = serviceInfo.getXmlSchemaCollection();
        this.prefixAccumulator = prefixAccumulator;
    }

    public String getCode() {
        return code.toString();
    }

    @Override
    public void begin(FaultInfo fault) {
    }

    @Override
    public void begin(InterfaceInfo intf) {
        code.append("\n// Javascript for " + intf.getName() + "\n\n");

        currentInterfaceClassName = nameManager.getJavascriptName(intf.getName());
        operationsWithNameConflicts = new HashSet<OperationInfo>();
        inputMessagesWithNameConflicts = new HashSet<MessageInfo>();
        outputMessagesWithNameConflicts = new HashSet<MessageInfo>();
        localOperationsNameMap = new HashMap<String, OperationInfo>();
        localInputMessagesNameMap = new HashMap<String, MessageInfo>();
        localOutputMessagesNameMap = new HashMap<String, MessageInfo>();

        code.append("function " + currentInterfaceClassName + " () {\n");
        utils.appendLine("this.jsutils = new CxfApacheOrgUtil();");
        utils.appendLine("this.jsutils.interfaceObject = this;");
        utils.appendLine("this.synchronous = false;");
        if (endpointAddress != null) {
            utils.appendLine("this.url = '" + endpointAddress + "';");
        } else {
            utils.appendLine("this.url = null;");
        }
        utils.appendLine("this.client = null;");
        utils.appendLine("this.response = null;");
        generateGlobalElementDictionary();
        code.append("}\n\n");
    }
    
    private void generateGlobalElementDictionary() {
        // to handle 'any', we need a dictionary of all the global elements of all the schemas.
        utils.appendLine("this.globalElementSerializers = [];");
        utils.appendLine("this.globalElementDeserializers = [];");
        for (XmlSchema schemaInfo : xmlSchemaCollection.getXmlSchemas()) {
            XmlSchemaObjectTable globalElements = schemaInfo.getElements();
            Iterator namesIterator = globalElements.getNames();
            while (namesIterator.hasNext()) {
                QName name = (QName)namesIterator.next();
                XmlSchemaElement element = (XmlSchemaElement) globalElements.getItem(name);
                // For now, at least, don't handle elements with simple types.
                // That comes later to improve deserialization.
                if (JavascriptUtils.notVeryComplexType(element.getSchemaType())) {
                    continue;
                }
                // If the element uses a named type, we use the functions for the type.
                XmlSchemaComplexType elementType = (XmlSchemaComplexType)element.getSchemaType();
                if (elementType != null && elementType.getQName() != null) {
                    name = elementType.getQName();
                }
                utils.appendLine("this.globalElementSerializers['" + name.toString() + "'] = "
                                 + nameManager.getJavascriptName(name)
                                 + "_serialize;");
                utils.appendLine("this.globalElementDeserializers['" + name.toString() + "'] = "
                                 + nameManager.getJavascriptName(name)
                                 + "_deserialize;");
            }
            
            globalElements = schemaInfo.getSchemaTypes();
            namesIterator = globalElements.getNames();
            while (namesIterator.hasNext()) {
                QName name = (QName)namesIterator.next();
                XmlSchemaType type = (XmlSchemaType) globalElements.getItem(name);
                // For now, at least, don't handle simple types.
                if (JavascriptUtils.notVeryComplexType(type)) {
                    continue;
                }
                // the names are misleading, but that's OK.
                utils.appendLine("this.globalElementSerializers['" + name.toString() + "'] = "
                                 + nameManager.getJavascriptName(name)
                                 + "_serialize;");
                utils.appendLine("this.globalElementDeserializers['" + name.toString() + "'] = "
                                 + nameManager.getJavascriptName(name)
                                 + "_deserialize;");
            }
        }
    }

    private String getFunctionGlobalName(QName itemName, String itemType) {
        return nameManager.getJavascriptName(itemName) + "_" + itemType; 
    }
    
    
    private<T> String getFunctionPropertyName(Set conflictMap, T object, QName fullName) {
        boolean needsLongName = conflictMap.contains(object);
        String functionName;
        if (needsLongName) {
            functionName = nameManager.getJavascriptName(fullName);
        } else {
            functionName = JavascriptUtils.javaScriptNameToken(fullName.getLocalPart());
        }
        return functionName;
        
    }

    // we do this at the end so we can inventory name conflicts sooner.
    @Override
    public void end(OperationInfo op) {
        // we only process the wrapped operation, not the unwrapped alternative.
        if (op.isUnwrapped()) {
            isInUnwrappedOperation = false;
            return;
        }

        isWrapped = op.isUnwrappedCapable();
        
        StringBuilder parameterList = new StringBuilder();

        inputParameterNames = new ArrayList<String>();
        
        if (isWrapped) {
            collectWrapperElementInfo();
        } else {
            collectUnwrappedInputInfo();
        }

        buildParameterList(parameterList);

        MessageInfo outputMessage = op.getOutput();
        nonVoidOutput = outputMessage != null && outputMessage.getMessageParts().size() != 0; 

        if (!op.isOneWay()) {
            buildSuccessFunction(outputMessage);
            buildErrorFunction(); // fault part some day.
        }

        buildOperationFunction(parameterList);

        createInputSerializer();

        if (nonVoidOutput) {
            createResponseDeserializer(outputMessage);
        } 
    }

    /**
     * visit the input message parts and collect relevant data.
     */
    private void collectUnwrappedInputInfo() {
        unwrappedElementsAndNames = new ArrayList<ParticleInfo>();
        if (currentOperation.getInput() != null) {
            getElementsForParts(currentOperation.getInput(), unwrappedElementsAndNames);
        }
        
        for (ParticleInfo ean : unwrappedElementsAndNames) {
            inputParameterNames.add(ean.getJavascriptName());
        }
    }
    
    

    private void buildOperationFunction(StringBuilder parameterList) {
        String responseCallbackParams = "";
        if (!currentOperation.isOneWay()) {
            responseCallbackParams = "successCallback, errorCallback";
        }
        
        MessageInfo inputMessage = currentOperation.getInput();

        code.append("//\n");
        code.append("// Operation " + currentOperation.getName() + "\n");
        if (!isWrapped) {
            code.append("// - bare operation. Parameters:\n");
            for (ParticleInfo ei : unwrappedElementsAndNames) {
                code.append("// - " + getElementObjectName(ei) + "\n");
            }
        } else {
            code.append("// Wrapped operation.\n");
            QName contextQName = inputWrapperComplexType.getQName();
            if (contextQName == null) {
                contextQName = inputWrapperElement.getQName();
            }
            XmlSchemaSequence sequence = XmlSchemaUtils.getSequence(inputWrapperComplexType);
            XmlSchema wrapperSchema = 
                xmlSchemaCollection.getSchemaByTargetNamespace(contextQName.getNamespaceURI());

            for (int i = 0; i < sequence.getItems().getCount(); i++) {
                code.append("// parameter " + inputParameterNames.get(i) + "\n");
                XmlSchemaObject sequenceItem = sequence.getItems().getItem(i);
                ParticleInfo itemInfo = ParticleInfo.forLocalItem(sequenceItem,
                                                                  wrapperSchema,
                                                                  xmlSchemaCollection,
                                                                  prefixAccumulator,
                                                                  contextQName); 
                if (itemInfo.isArray()) {
                    code.append("// - array\n");
                }
                
                XmlSchemaType type = itemInfo.getType(); // null for an any.
                if (type instanceof XmlSchemaComplexType) {
                    QName baseName;
                    if (type.getQName() != null) {
                        baseName = type.getQName();
                    } else {
                        baseName = ((XmlSchemaElement)sequenceItem).getQName();
                    }
                    code.append("// - Object constructor is " 
                                    + nameManager.getJavascriptName(baseName) + "\n");
                } else if (type != null) {
                    code.append("// - simple type " + type.getQName());
                }
            }       
        }
        
        code.append("//\n");
        
        code.append("function " 
                    +  opFunctionGlobalName
                    + "("  + responseCallbackParams
                    + ((parameterList.length() > 0 && !currentOperation.isOneWay()) 
                        ? ", " : "") + parameterList + ") {\n");
        utils.appendLine("this.client = new CxfApacheOrgClient(this.jsutils);");
        utils.appendLine("var xml = null;");
        if (inputMessage != null) {
            utils.appendLine("var args = new Array(" + inputParameterNames.size() + ");");
            int px = 0;
            for (String param : inputParameterNames) {
                utils.appendLine("args[" + px + "] = " + param + ";");
                px++;
            }
            utils.appendLine("xml = this."
                             + getFunctionPropertyName(inputMessagesWithNameConflicts,
                                                       inputMessage, 
                                                       inputMessage.getName())
                             + "_serializeInput"
                             + "(this.jsutils, args);");
        }

        // we need to pass the caller's callback functions to our callback
        // functions.
        if (!currentOperation.isOneWay()) {
            utils.appendLine("this.client.user_onsuccess = successCallback;");
            utils.appendLine("this.client.user_onerror = errorCallback;");
            utils.appendLine("var closureThis = this;");
            // client will pass itself and the response XML.
            utils.appendLine("this.client.onsuccess = function(client, responseXml) { closureThis." 
                                 + opFunctionPropertyName
                                 + "_onsuccess(client, responseXml); };");
            // client will pass itself.
            utils.appendLine("this.client.onerror = function(client) { closureThis."
                             + opFunctionPropertyName
                             + "_onerror(client); };");
        }
        utils.appendLine("var requestHeaders = [];");

        if (soapBindingInfo != null) {
            String action = soapBindingInfo.getSoapAction(currentOperation);
            utils.appendLine("requestHeaders['SOAPAction'] = '" + action + "';");
        }

        // default 'method' by passing null. Is there some place this lives in the
        // service model?
        String syncAsyncFlag;
        if (currentOperation.isOneWay()) {
            utils.appendLine("this.jsutils.trace('oneway operation');");
            syncAsyncFlag = "false";
        } else {
            utils.appendLine("this.jsutils.trace('synchronous = ' + this.synchronous);");
            syncAsyncFlag = "this.synchronous";
        }
        utils.appendLine("this.client.request(this.url, xml, null, "
                         + syncAsyncFlag + ", requestHeaders);");

        code.append("}\n\n");
        code.append(currentInterfaceClassName + ".prototype." 
                    + opFunctionPropertyName 
                    + " = " 
                    + opFunctionGlobalName
                    + ";\n\n");
    }

    private void buildErrorFunction() {
        String errorFunctionPropertyName = opFunctionPropertyName + "_onerror";
        String errorFunctionGlobalName = opFunctionGlobalName + "_onerror";
        
        code.append("function " + errorFunctionGlobalName + "(client) {\n");
        utils.startIf("client.user_onerror");
        // Is this a good set of parameters for the error function?
        // Not if we want to process faults, it isn't. To be revisited.
        utils.appendLine("var httpStatus;");
        utils.appendLine("var httpStatusText;");
        utils.appendLine("try {");
        utils.appendLine(" httpStatus = client.req.status;");
        utils.appendLine(" httpStatusText = client.req.statusText;");
        utils.appendLine("} catch(e) {");
        utils.appendLine(" httpStatus = -1;");
        utils.appendLine(" httpStatusText = 'Error opening connection to server';");
        utils.appendLine("}");
        utils.appendLine("client.user_onerror(httpStatus, httpStatusText);");
        utils.endBlock();
        code.append("}\n\n");
        code.append(currentInterfaceClassName + ".prototype." 
                    + errorFunctionPropertyName 
                    + " = "
                    + errorFunctionGlobalName 
                    + ";\n\n");
    }

    // Note: the response XML that we get from the XMLHttpRequest is the document element,
    // not the root element.
    private void buildSuccessFunction(MessageInfo outputMessage) {
        // Here are the success and error callbacks. They have the job of
        // calling callbacks provided to the operation function with appropriate
        // parameters.
        String successFunctionGlobalName = opFunctionGlobalName + "_onsuccess"; 
        String successFunctionPropertyName = opFunctionPropertyName + "_onsuccess"; 
        String arglist = "(client)";
        if (nonVoidOutput) {
            arglist = "(client, responseXml)";
        }
        
        code.append("function " + successFunctionGlobalName + arglist + " {\n");
        utils.startIf("client.user_onsuccess");
        utils.appendLine("var responseObject = null;");
        if (nonVoidOutput) {
            utils.appendLine("var element = responseXml.documentElement;");
            utils.appendLine("this.jsutils.trace('responseXml: ' "
                             + "+ this.jsutils.traceElementName(element));");

            if (soapBindingInfo != null) { // soap
                // The following code is probably only right for basic
                // Doc/Literal/Wrapped services.
                // the top element should be the Envelope, then the Body, then
                // the actual response item.
                utils.appendLine("element = this.jsutils.getFirstElementChild(element);");
                utils.appendLine("this.jsutils.trace('first element child: ' "
                                 + "+ this.jsutils.traceElementName(element));");
                // loop to find the body.
                utils.startWhile("!this.jsutils.isNodeNamedNS(element, "
                                 + "'http://schemas.xmlsoap.org/soap/envelope/', 'Body')");
                utils.appendLine("element = this.jsutils.getNextElementSibling(element);");
                utils.startIf("element == null");
                utils.appendLine("throw 'No env:Body in message.'");
                utils.endBlock();
                utils.endBlock();
                // Go down one more from the body to the response item.
                utils.appendLine("element = this.jsutils.getFirstElementChild(element);");
                utils.appendLine("this.jsutils.trace('part element: ' "
                                 + "+ this.jsutils.traceElementName(element));");
            } 
            String deserializerFunctionName = outputDeserializerFunctionName(outputMessage);
            utils.appendLine("this.jsutils.trace('calling " + deserializerFunctionName + "');");
            utils.appendLine("responseObject = " + deserializerFunctionName + "(this.jsutils, element);");
        }
        utils.appendLine("client.user_onsuccess(responseObject);");
        utils.endBlock();
        code.append("}\n\n");
        code.append(currentInterfaceClassName + ".prototype." 
                    + successFunctionPropertyName 
                    + " = "
                    + successFunctionGlobalName + ";\n\n");
    }

    private void buildParameterList(StringBuilder parameterList) {
        for (String param : inputParameterNames) {
            parameterList.append(param);
            parameterList.append(", ");
        }
        // trim last comma.
        if (parameterList.length() > 2) {
            parameterList.setLength(parameterList.length() - 2);
        }
    }

    private String outputDeserializerFunctionName(MessageInfo message) {
        return getFunctionGlobalName(message.getName(), "deserializeResponse");
    }

    // This ignores 'wrapped', because it assumes one part that we can use one way or 
    // the other. For simple cases, this is certainly OK.
    private void createResponseDeserializer(MessageInfo outputMessage) {
        List<MessagePartInfo> parts = outputMessage.getMessageParts();
        if (parts.size() != 1) {
            unsupportedConstruct("MULTIPLE_OUTPUTS", outputMessage.getName().toString());
        }
        List<ParticleInfo> elements = new ArrayList();
        String functionName = outputDeserializerFunctionName(outputMessage);
        code.append("function " + functionName + "(cxfjsutils, partElement) {\n");
        getElementsForParts(outputMessage, elements);
        ParticleInfo element = elements.get(0);
        XmlSchemaType type = null;
        
        if (isRPC) {
            utils.appendLine("cxfjsutils.trace('rpc element: ' + cxfjsutils.traceElementName(partElement));");
            utils.appendLine("partElement = cxfjsutils.getFirstElementChild(partElement);");
            utils.appendLine("cxfjsutils.trace('rpc element: ' + cxfjsutils.traceElementName(partElement));");
        }
        
        type = element.getType();
        
        if (!element.isEmpty()) {
            if (type instanceof XmlSchemaComplexType) {
                String typeObjectName = nameManager.getJavascriptName(element.getControllingName());
                utils
                    .appendLine("var returnObject = " 
                                + typeObjectName 
                                + "_deserialize (cxfjsutils, partElement);\n");
            } else if (type instanceof XmlSchemaSimpleType) {
                XmlSchemaSimpleType simpleType = (XmlSchemaSimpleType)type;
                utils.appendLine("var returnText = cxfjsutils.getNodeText(partElement);");
                utils.appendLine("var returnObject = " 
                                 + utils.javascriptParseExpression(simpleType, "returnText") + ";");
            } 
            utils.appendLine("return returnObject;");
        }
        code.append("}\n");
    }
    
    private String getElementObjectName(ParticleInfo element) {
        XmlSchemaType type = element.getType();

        if (!element.isEmpty()) {
            if (type instanceof XmlSchemaComplexType) {
                return nameManager.getJavascriptName(element.getControllingName());
            } else {
                return "type " + type.getQName(); // could it be anonymous?
            } 
        } else {
            return "empty element?";
        }
    }

    private void createInputSerializer() {
        
        // If are working on a wrapped method, then we use the wrapper element.
        // If we are working on an unwrapped method, we will have to work from the unwrapped parts.
        
        MessageInfo message = currentOperation.getInput();
        String serializerFunctionGlobalName = getFunctionGlobalName(message.getName(), "serializeInput");
        String serializerFunctionPropertyName = 
            getFunctionPropertyName(inputMessagesWithNameConflicts, message, message.getName())
            + "_serializeInput";

        code.append("function " + serializerFunctionGlobalName + "(cxfjsutils, args) {\n");

        String wrapperXmlElementName = null; 
        // for the wrapped case, we can name the object for Javascript after whatever we like.
        // we could use the wrapped part, or we could use a conventional name.
        if (isWrapped) {
            wrapperXmlElementName = 
                prefixAccumulator.xmlElementString(inputWrapperPartInfo.getConcreteName());
            utils.appendLine("var wrapperObj = new " + inputWrapperClassName + "();");
            int px = 0;
            for (String param : inputParameterNames) {
                utils.appendLine("wrapperObj.set" + StringUtils.capitalize(param) + "(args[" + px
                                 + "]);");
                px++;
            }
        }

        if (soapBindingInfo != null) {
            SoapVersion soapVersion = soapBindingInfo.getSoapVersion();
            assert soapVersion.getVersion() == 1.1;
            utils.appendLine("var xml;");
            utils.appendLine("xml = cxfjsutils.beginSoap11Message(\"" + prefixAccumulator.getAttributes()
                             + "\");");
        } else {
            // other alternative is XML, which isn't really all here yet.
            unsupportedConstruct("XML_BINDING", currentInterfaceClassName, xmlBindingInfo.getName());
        }

        utils.setXmlStringAccumulator("xml");
        
        if (isWrapped) {
            ParticleInfo elementInfo = ParticleInfo.forPartElement(inputWrapperElement,
                                                                 xmlSchemaCollection,
                                                                 "wrapperObj",
                                                                 wrapperXmlElementName);

            elementInfo.setContainingType(null);
            utils.generateCodeToSerializeElement(elementInfo, "", xmlSchemaCollection);
        } else {
            String operationXmlElement = null;
            if (isRPC) {
                operationXmlElement = 
                    prefixAccumulator.xmlElementString(currentOperation.getName());

                // RPC has a level of element for the entire operation.
                // we might have some schema to model this, but the following seems
                // sufficient.
                utils.appendString("<" + operationXmlElement + ">");                
            }
            int px = 0;
            // Multiple parts for document violates WS-I, but we can still do them.
            // They are normal for RPC.
            // Parts are top-level elements. As such, they cannot, directly, be arrays.
            // If a part is declared as an array type, the schema has a non-array element
            // with a complex type consisting of an element with array bounds. We don't 
            // want the JavasSript programmer to have to concoct an extra level of object
            // (though if the same sort of thing happens elsewhere due to an XmlRootElement,
            // the JavaScript programmer is stuck with the situation). 
            for (ParticleInfo ean : unwrappedElementsAndNames) {
                String savedjsName = ean.getJavascriptName();
                try {
                    ean.setJavascriptName("args[" + px + "]");
                    utils.generateCodeToSerializeElement(ean, "", xmlSchemaCollection);
                    px++;
                } finally {
                    ean.setJavascriptName(savedjsName);
                    
                }
            }
            if (isRPC) {
                utils.appendString("</" + operationXmlElement + ">");                
            }
        }

        utils.appendLine("xml = xml + cxfjsutils.endSoap11Message();");
        utils.appendLine("return xml;");
        code.append("}\n\n");
        code.append(currentInterfaceClassName + ".prototype."
                    + serializerFunctionPropertyName 
                    + " = "
                    + serializerFunctionGlobalName + ";\n\n");
    }
    
    private XmlSchemaSequence getTypeSequence(XmlSchemaComplexType type, 
                                              QName parentName) {
        if (!(type.getParticle() instanceof XmlSchemaSequence)) {
            unsupportedConstruct("NON_SEQUENCE_PARTICLE", 
                                 type.getQName() != null ? type.getQName() 
                                     :
                                     parentName);
        }
        return (XmlSchemaSequence)type.getParticle();
    }
    
    private boolean isEmptyType(XmlSchemaType type, QName parentName) {
        if (type instanceof XmlSchemaComplexType) {
            XmlSchemaComplexType complexType = (XmlSchemaComplexType)type;
            if (complexType.getParticle() == null) {
                return true;
            } 
            XmlSchemaSequence sequence = getTypeSequence(complexType, parentName);
            if (sequence.getItems().getCount() == 0) {
                return true;
            }
        }
        return false;
    }
    
    private XmlSchemaParticle getBuriedElement(XmlSchemaComplexType type, 
                                              QName parentName) {
        XmlSchemaSequence sequence = getTypeSequence(type, parentName);
        XmlSchemaObjectCollection insides = sequence.getItems();
        if (insides.getCount() == 1) {
            XmlSchemaObject item = insides.getItem(0);
            if (item instanceof XmlSchemaElement || item instanceof XmlSchemaAny) {
                return (XmlSchemaParticle) item;
            }
        }
        return null;
    }

    /**
     * Collect information about the parts of an unwrapped message.
     * @param parts 
     * @param elements
     */
    private void getElementsForParts(MessageInfo message, List<ParticleInfo> elements) {
        for (MessagePartInfo mpi : message.getMessageParts()) {
            XmlSchemaElement element = null;
            XmlSchemaType type = null; 
            QName diagnosticName = mpi.getName();
            if (mpi.isElement()) {
                element = (XmlSchemaElement)mpi.getXmlSchema();
                if (element == null) {
                    element = XmlSchemaUtils.findElementByRefName(xmlSchemaCollection, mpi.getElementQName(),
                                                                  serviceInfo.getTargetNamespace());
                }
                diagnosticName = element.getQName();
                type = element.getSchemaType();
                if (type == null) {
                    type = XmlSchemaUtils.getElementType(xmlSchemaCollection, 
                                                         null, 
                                                         element, 
                                                         null);
                }
            } else {
                // RPC (!isElement)
                type = (XmlSchemaType)mpi.getXmlSchema();
                if (type == null) {
                    type = xmlSchemaCollection.getTypeByQName(mpi.getTypeQName());
                    diagnosticName = type.getQName();
                }
               
            }
            
            boolean empty = isEmptyType(type, diagnosticName);
            // There's something funny about doc/bare. Since it's doc, there is no
            // element in the part. There is a type. However, for some reason,
            // it tends to be an anonymous complex type containing an element, and that
            // element corresponds to the type of the parameter. So, we refocus on that.
            if (!empty 
                && type instanceof XmlSchemaComplexType 
                && type.getName() == null 
                && !isWrapped) {
                XmlSchemaParticle betterElement = getBuriedElement((XmlSchemaComplexType) type,
                                                                  diagnosticName);
                if (betterElement instanceof XmlSchemaElement) {
                    element = (XmlSchemaElement)betterElement;
                    if (element.getSchemaType() == null) {
                        if (element.getSchemaTypeName() != null) {
                            element.setSchemaType(xmlSchemaCollection
                                                  .getTypeByQName(element.getSchemaTypeName()));
                        } else if (element.getRefName() != null) {
                            element = xmlSchemaCollection.getElementByQName(element.getRefName());
                            element.setSchemaType(xmlSchemaCollection
                                                  .getTypeByQName(element.getSchemaTypeName()));
                        }
                    }
                    type = element.getSchemaType();
                }
            }
            
            String partJavascriptVar = 
                JavascriptUtils.javaScriptNameToken(mpi.getConcreteName().getLocalPart());
            String elementXmlRef = prefixAccumulator.xmlElementString(mpi.getConcreteName());
            ParticleInfo elementInfo = ParticleInfo.forPartElement(element,
                                                                 xmlSchemaCollection,
                                                                 partJavascriptVar, 
                                                                 elementXmlRef);        
            // the type may have been recalculated above.
            elementInfo.setType(type);
            elementInfo.setEmpty(empty);
            elements.add(elementInfo);
        }
    }
    
    // This function finds all the information for the wrapper.
    private void collectWrapperElementInfo() {
        
        if (currentOperation.getInput() != null) {
            inputWrapperPartInfo = currentOperation.getInput().getMessagePart(0);

            List<MessagePartInfo> unwrappedParts = 
                currentOperation.getUnwrappedOperation().getInput().getMessageParts();

            for (MessagePartInfo mpi : unwrappedParts) {
                String jsParamName = JavascriptUtils.javaScriptNameToken(mpi.getName().getLocalPart());
                inputParameterNames.add(jsParamName);
            }

            inputWrapperPartInfo = currentOperation.getInput().getMessagePart(0);
            assert inputWrapperPartInfo.isElement();

            inputWrapperElement = (XmlSchemaElement)inputWrapperPartInfo.getXmlSchema();
            if (inputWrapperElement == null) {
                inputWrapperElement = 
                    XmlSchemaUtils.findElementByRefName(xmlSchemaCollection, 
                                                        inputWrapperPartInfo.getElementQName(),
                                                        serviceInfo.getTargetNamespace());
            }
            inputWrapperComplexType = (XmlSchemaComplexType)inputWrapperElement.getSchemaType();
            // the null name is probably something awful in RFSB.
            if (inputWrapperComplexType == null) {
                inputWrapperComplexType = (XmlSchemaComplexType)
                    XmlSchemaUtils.getElementType(xmlSchemaCollection, 
                                                  serviceInfo.getTargetNamespace(), 
                                                  inputWrapperElement, 
                                                  null);
            }
            if (inputWrapperComplexType == null) {
                unsupportedConstruct("MISSING_WRAPPER_TYPE",
                                     currentOperation.getInterface().getName(),
                                     currentOperation.getName(), 
                                     inputWrapperPartInfo.getName());
            }
            
            if (inputWrapperComplexType.getQName() == null) {
                // we should be ignoring this for zero-argument wrappers.
                if (inputWrapperPartInfo.isElement()) {
                    inputWrapperClassName = nameManager.
                        getJavascriptName(inputWrapperPartInfo.getElementQName());
                } else {
                    unsupportedConstruct("NON_ELEMENT_ANON_TYPE_PART", 
                                         inputWrapperPartInfo.getMessageInfo().getName(),
                                         inputWrapperPartInfo.getName());
                }
            } else {
                inputWrapperClassName = nameManager.getJavascriptName(inputWrapperComplexType.getQName());
            }
            
        }

        if (currentOperation.getOutput() != null) {
            outputWrapperPartInfo = currentOperation.getOutput().getMessagePart(0);
            assert outputWrapperPartInfo.isElement();

            outputWrapperElement = (XmlSchemaElement)outputWrapperPartInfo.getXmlSchema();
            if (outputWrapperElement == null) {
                outputWrapperElement = 
                    XmlSchemaUtils.findElementByRefName(xmlSchemaCollection, 
                                                        outputWrapperPartInfo.getElementQName(),
                                                        serviceInfo.getTargetNamespace());
            }
            outputWrapperComplexType = (XmlSchemaComplexType)outputWrapperElement.getSchemaType();
            if (outputWrapperComplexType == null) {
                outputWrapperComplexType = (XmlSchemaComplexType)
                    XmlSchemaUtils.getElementType(xmlSchemaCollection, 
                                                  serviceInfo.getTargetNamespace(), 
                                                  outputWrapperElement, 
                                                  null);
            }
        }
    }

    @Override
    public void begin(ServiceInfo service) {
        
        code.append("//\n");
        code.append("// Definitions for service: " + service.getName().toString() + "\n");
        code.append("//\n");

        BindingInfo xml = null;
        // assume only one soap binding.
        // until further consideration.
        // hypothetically, we could generate two different JavaScript classes,
        // one for each.
        for (BindingInfo bindingInfo : service.getBindings()) {
            // there is a JIRA about the confusion / profusion of URLS here.
            if (SoapBindingConstants.SOAP11_BINDING_ID.equals(bindingInfo.getBindingId())
                || SoapBindingConstants.SOAP12_BINDING_ID.equals(bindingInfo.getBindingId())
                || SoapBindingFactory.SOAP_11_BINDING.equals(bindingInfo.getBindingId())
                || SoapBindingFactory.SOAP_12_BINDING.equals(bindingInfo.getBindingId())
                ) {
                SoapBindingInfo sbi = (SoapBindingInfo)bindingInfo;
                if (WSDLConstants.NS_SOAP11_HTTP_TRANSPORT.equals(sbi.getTransportURI())
                    || WSDLConstants.NS_SOAP12_HTTP_BINDING.equals(sbi.getTransportURI())
                    // we may want this for testing.
                    || LocalTransportFactory.TRANSPORT_ID.equals(sbi.getTransportURI())) {
                    soapBindingInfo = sbi;
                    break;
                }
            } else if (WSDLConstants.NS_BINDING_XML.equals(bindingInfo.getBindingId())) {
                xml = bindingInfo;
            }
        }

        // For now, we use soap if its available, and XML if it isn't.\
        if (soapBindingInfo == null && xml == null) {
            unsupportedConstruct("NO_USABLE_BINDING", service.getName());
        }

        if (soapBindingInfo != null) {
            isRPC = WSDLConstants.RPC.equals(soapBindingInfo.getStyle());
        } else if (xml != null) {
            xmlBindingInfo = xml;
        }
    }

    @Override
    public void end(FaultInfo fault) {
    }

    @Override
    public void end(InterfaceInfo intf) {
    }

    @Override
    public void end(MessageInfo msg) {
    }

    @Override
    public void end(MessagePartInfo part) {
    }

    @Override
    public void end(ServiceInfo service) {
        LOG.finer(getCode());
    }

    private void unsupportedConstruct(String messageKey, Object... args) {
        Message message = new Message(messageKey, LOG, args);
        throw new UnsupportedConstruct(message);
    }

    @Override
    public void begin(OperationInfo op) {
        if (op.isUnwrapped()) {
            isInUnwrappedOperation = true;
            return;
        }
        currentOperation = op;
        OperationInfo conflict = localOperationsNameMap.get(op.getName().getLocalPart());
        if (conflict != null) {
            operationsWithNameConflicts.add(conflict);
            operationsWithNameConflicts.add(op);
        }
        localOperationsNameMap.put(op.getName().getLocalPart(), op);
        opFunctionPropertyName = getFunctionPropertyName(operationsWithNameConflicts, op, op.getName());
        opFunctionGlobalName = getFunctionGlobalName(op.getName(), "op");
    }
    
    @Override
    public void begin(MessageInfo msg) {
        if (isInUnwrappedOperation) {
            return;
        }
        LOG.fine("Message " + msg.getName().toString());
        Map<String, MessageInfo> nameMap;
        Set<MessageInfo> conflicts;
        if (msg.getType() == MessageInfo.Type.INPUT) {
            nameMap = localInputMessagesNameMap;
            conflicts = inputMessagesWithNameConflicts;
        } else {
            nameMap = localOutputMessagesNameMap;
            conflicts = outputMessagesWithNameConflicts;

        }
        MessageInfo conflict = nameMap.get(msg.getName().getLocalPart());
        if (conflict != null) {
            conflicts.add(conflict);
            conflicts.add(msg);
        }
        nameMap.put(msg.getName().getLocalPart(), msg);
    }

    @Override
    public void begin(EndpointInfo endpointInfo) {
        String address = endpointInfo.getAddress();
        String portClassName = currentInterfaceClassName + "_" 
            + nameManager.getJavascriptName(endpointInfo.getName());
        code.append("function " + portClassName + " () {\n");
        code.append("  this.url = '" + address + "';\n");
        code.append("}\n");
        code.append(portClassName + ".prototype = new " + currentInterfaceClassName + ";\n");
    }


}

Other Apache CXF examples (source code examples)

Here is a short list of links related to this Apache CXF ServiceJavascriptBuilder.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.