org.ebayopensource.turmeric.eclipse.template.wsdl.util.ServiceTemplateUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.ebayopensource.turmeric.eclipse.template.wsdl.util.ServiceTemplateUtil.java

Source

/*******************************************************************************
 * Copyright (c) 2006-2010 eBay Inc. All Rights Reserved.
 * Licensed 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
 *******************************************************************************/
package org.ebayopensource.turmeric.eclipse.template.wsdl.util;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Set;

import javax.xml.namespace.QName;

import org.apache.commons.lang.StringUtils;
import org.ebayopensource.turmeric.common.config.LibraryType;
import org.ebayopensource.turmeric.eclipse.core.model.IParameterElement;
import org.ebayopensource.turmeric.eclipse.core.resources.constants.SOAProjectConstants.TemplateBinding;
import org.ebayopensource.turmeric.eclipse.core.resources.constants.SOATypeLibraryConstants;
import org.ebayopensource.turmeric.eclipse.exception.core.CommandFailedException;
import org.ebayopensource.turmeric.eclipse.repositorysystem.core.GlobalRepositorySystem;
import org.ebayopensource.turmeric.eclipse.repositorysystem.core.SOAGlobalRegistryAdapter;
import org.ebayopensource.turmeric.eclipse.template.wsdl.resources.SOAMessages;
import org.ebayopensource.turmeric.eclipse.typelibrary.ui.TypeLibraryUIActivator;
import org.ebayopensource.turmeric.eclipse.typelibrary.ui.TypeLibraryUtil;
import org.ebayopensource.turmeric.eclipse.typelibrary.ui.wst.WTPTypeLibUtil;
import org.ebayopensource.turmeric.eclipse.utils.lang.StringUtil;
import org.eclipse.wst.wsdl.Binding;
import org.eclipse.wst.wsdl.Definition;
import org.eclipse.wst.wsdl.Input;
import org.eclipse.wst.wsdl.Message;
import org.eclipse.wst.wsdl.MessageReference;
import org.eclipse.wst.wsdl.Operation;
import org.eclipse.wst.wsdl.Output;
import org.eclipse.wst.wsdl.Part;
import org.eclipse.wst.wsdl.PortType;
import org.eclipse.wst.wsdl.WSDLFactory;
import org.eclipse.wst.wsdl.internal.generator.BindingGenerator;
import org.eclipse.wst.wsdl.internal.generator.extension.ContentGeneratorExtensionFactoryRegistry;
import org.eclipse.wst.wsdl.ui.internal.commands.AddMessageCommand;
import org.eclipse.wst.wsdl.ui.internal.commands.AddPartCommand;
import org.eclipse.wst.wsdl.ui.internal.util.NameUtil;
import org.eclipse.wst.wsdl.ui.internal.util.XSDComponentHelper;
import org.eclipse.xsd.XSDComplexTypeDefinition;
import org.eclipse.xsd.XSDCompositor;
import org.eclipse.xsd.XSDDerivationMethod;
import org.eclipse.xsd.XSDElementDeclaration;
import org.eclipse.xsd.XSDFactory;
import org.eclipse.xsd.XSDImport;
import org.eclipse.xsd.XSDModelGroup;
import org.eclipse.xsd.XSDParticle;
import org.eclipse.xsd.XSDSchema;
import org.eclipse.xsd.XSDTypeDefinition;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
 * The Utility class to serve the Service template processors and other template
 * classes. This class has methods to create the WSDL, manipulate it i.e add
 * operation, elements etc. Basically this class manipulates the WSDL using the
 * WTP EMF model and expose the manipulating functionalities SOA require. It
 * also has getters for accessing the the WSDL properties like the port,
 * operations, elements etc. Has the binding generation responsibility also.
 * 
 * @author smathew
 * 
 */
public class ServiceTemplateUtil {

    /**
     * Gets the default port in a definition object. The default is the first
     * port type available in the WSDL. If the definition does not have any port
     * types then it creates a new one, add it to the definition and returns it.
     *
     * @param definition the definition
     * @return the default port
     */
    public static PortType getDefaultPort(Definition definition) {
        PortType portType = null;
        if (definition.getPortTypes() != null) {
            Iterator<?> iterator = definition.getPortTypes().values().iterator();
            while (iterator.hasNext()) {
                Object objPortType = iterator.next();
                if (objPortType != null && objPortType instanceof PortType) {
                    portType = (PortType) objPortType;
                    break;
                }
            }
        }
        if (portType == null) {
            portType = WSDLFactory.eINSTANCE.createPortType();
            portType.setQName(
                    new QName(definition.getTargetNamespace(), ServiceTemplateConstants.DEFAULT_PORT_NAME));
            portType.setEnclosingDefinition(definition);
            definition.addPortType(portType);
        }
        return portType;
    }

    /**
     * Returns true if the operation with with given name exists in the given
     * port type. This is a case sensitive API. Remember an operation with the
     * same name can exist in the WSDL under a different port type and clients
     * are supposed to use this API with different port types to achieve a full
     * length uniqueness.
     *
     * @param portType the port type
     * @param opName the op name
     * @return true, if successful
     */
    public static boolean operationExists(PortType portType, String opName) {
        for (Object operationObject : portType.getOperations()) {
            if (operationObject instanceof Operation) {
                if (StringUtils.equals(((Operation) operationObject).getName(), opName)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Adds an operation with the given name to the port type. Does not check
     * for existing operations. In that case clients can use
     *
     * @param portType the port type
     * @param operationName the operation name
     * @return the operation
     * @see ServiceTemplateUtil#operationExists(PortType, String) API before
     * calling this API.
     */
    public static Operation addOperation(PortType portType, String operationName) {
        Operation operation = WSDLFactory.eINSTANCE.createOperation();
        operation.setName(operationName);
        operation.setEnclosingDefinition(portType.getEnclosingDefinition());
        if (portType.getElement() != null && portType.getElement().getOwnerDocument() != null) {
            //adding the wsdl:documentation tag to the PortType->Operation
            final Document ownerDoc = portType.getElement().getOwnerDocument();
            final Element element = ownerDoc.createElement(ServiceTemplateConstants.TAG_DOCUMENTATION_ELEMENT);
            element.appendChild(ownerDoc.createTextNode(ServiceTemplateConstants.DEFAULT_DOCUMENT_TEXT));
            operation.setDocumentationElement(element);
        }

        portType.addOperation(operation);
        return operation;
    }

    /**
     * Adds the specified input parameter to the operation, creates a message
     * for it and return the part. Remember for setting the input parameter we
     * need the message and part to be added as well.
     *
     * @param operation the operation
     * @param inputParamName the input param name
     * @return the part
     * @throws CommandFailedException the command failed exception
     */
    public static Part addInput(Operation operation, String inputParamName) throws CommandFailedException {
        MessageReference messageReference = WSDLFactory.eINSTANCE.createInput();
        messageReference.setEnclosingDefinition(operation.getEnclosingDefinition());
        operation.setInput((Input) messageReference);
        return createMessage(operation, inputParamName, messageReference);

    }

    /**
     * Adds the specified output parameter to the operation, creates a message
     * for it and return the part. Remember for setting the output parameter we
     * need the message and part to be added as well.
     *
     * @param operation the operation
     * @param outputParamName the output param name
     * @return the part
     * @throws CommandFailedException the command failed exception
     */
    public static Part addOutput(Operation operation, String outputParamName) throws CommandFailedException {
        MessageReference messageReference = WSDLFactory.eINSTANCE.createOutput();
        messageReference.setEnclosingDefinition(operation.getEnclosingDefinition());
        operation.setOutput((Output) messageReference);
        return createMessage(operation, outputParamName, messageReference);
    }

    /**
     * Creates the message with the given message name. The WSDL definition is
     * automatically discovered from the operation passed. Finally the part is
     * also created with this message and returned to the client.
     *
     * @param operation the operation
     * @param messageName the message name
     * @param messageReference the message reference
     * @return the part
     * @throws CommandFailedException the command failed exception
     */
    public static Part createMessage(Operation operation, String messageName, MessageReference messageReference)
            throws CommandFailedException {
        Definition definition = operation.getEnclosingDefinition();
        AddMessageCommand command = new AddMessageCommand(definition, messageName, false);
        command.run();
        messageReference.setEMessage((Message) command.getWSDLElement());
        return createPart((Message) command.getWSDLElement());
    }

    /**
     * Creates the part for the message, the name of the part is the default
     * name and the name space and name are discovered from the message
     * parameter. It used the WTP EMF based command internally.
     *
     * @param message the message
     * @return the part
     */
    public static Part createPart(Message message) {
        AddPartCommand command = new AddPartCommand(message, ServiceTemplateConstants.DEFAULT_PART_NAME,
                message.getQName().getNamespaceURI(), message.getQName().getLocalPart(), false);
        command.run();
        return (Part) command.getWSDLElement();
    }

    /**
     * Wrapper over the method.
     *
     * @param part the part
     * @param operation the operation
     * @param typeFolding the type folding
     * @return the xSD complex type definition
     * @throws CommandFailedException the command failed exception
     * @see ServiceTemplateUtil#createXSDElementDefinition(String, Part, String,
     * String).
     * 
     * The input parameter element name is computed from the part name using the
     * WTP API and the operation parameter. The base service request type name
     * and name space are parsed from the "service_config.properties" and passed
     * to the API
     */
    public static XSDComplexTypeDefinition createInputComplexType(Part part, Operation operation,
            boolean typeFolding) throws CommandFailedException {
        return createXSDElementDefinition(NameUtil.getPartName(operation.getEInput()), part,
                GlobalRepositorySystem.instanceOf().getActiveRepositorySystem().getConfigurationRegistry()
                        .getBaseServiceRequestType(),
                GlobalRepositorySystem.instanceOf().getActiveRepositorySystem().getConfigurationRegistry()
                        .getBaseServiceRequestNameSpace(),
                typeFolding, operation.getEnclosingDefinition().getTargetNamespace());

    }

    /**
     * Wrapper over the method.
     *
     * @param part the part
     * @param operation the operation
     * @param typeFolding the type folding
     * @return the xSD complex type definition
     * @throws CommandFailedException the command failed exception
     * @see ServiceTemplateUtil#createXSDElementDefinition(String, Part, String,
     * String).
     * 
     * The output parameter element name is computed from the part name using
     * the WTP API and the operation parameter. The base service response type
     * name and name space are parsed from the "service_config.properties" and
     * passed to the API
     */
    public static XSDComplexTypeDefinition createOutputComplexType(Part part, Operation operation,
            boolean typeFolding) throws CommandFailedException {
        return createXSDElementDefinition(NameUtil.getPartName(operation.getEOutput()), part,
                GlobalRepositorySystem.instanceOf().getActiveRepositorySystem().getConfigurationRegistry()
                        .getBaseServiceResponseType(),
                GlobalRepositorySystem.instanceOf().getActiveRepositorySystem().getConfigurationRegistry()
                        .getBaseServiceResponseNameSpace(),
                typeFolding, operation.getEnclosingDefinition().getTargetNamespace());
    }

    /**
     * Add the element declaration based on the parameter element passed. The
     * default w3c data types will carry the prefix from corresponding to w3c
     * name space and rest all will be computed and if the prefix does not exist
     * then it is added before using it.
     *
     * @param parameterElement the parameter element
     * @param complexTypeDefinition the complex type definition
     * @param typeFolding the type folding
     * @throws CommandFailedException the command failed exception
     */
    public static void addElementDeclaration(IParameterElement parameterElement,
            XSDComplexTypeDefinition complexTypeDefinition, boolean typeFolding) throws CommandFailedException {
        String prefixedElementType = "";
        if (parameterElement.getDatatype() instanceof String) {
            prefixedElementType = TypeLibraryUIActivator.getPrefix(complexTypeDefinition.getSchema(),
                    SOATypeLibraryConstants.W3C_NAMEPSACE) + (String) parameterElement.getDatatype();
        } else {
            try {
                LibraryType libElementType = (LibraryType) parameterElement.getDatatype();
                String elementName = libElementType.getName();
                String elementNamespace = typeFolding ? complexTypeDefinition.getTargetNamespace()
                        : TypeLibraryUtil.getNameSpace(libElementType);
                prefixedElementType = TypeLibraryUIActivator.getPrefix(complexTypeDefinition.getSchema(),
                        elementNamespace) + elementName;
            } catch (Exception e) {
                throw new CommandFailedException(
                        StringUtil.formatString(SOAMessages.TYPE_NOT_FOUND, parameterElement.getDatatype()));
            }
        }
        XSDParticle xsdParticle = TypeLibraryUIActivator.createXSDElementDeclaration(parameterElement.getName(),
                prefixedElementType, parameterElement.getMinOccurs(), parameterElement.getMaxOccurs());
        XSDModelGroup xsdModelGroup = TypeLibraryUIActivator.getModelGroup(complexTypeDefinition);
        xsdModelGroup.getContents().add(xsdParticle);

    }

    /**
     * Adds a binding to the definition model being used. Here we have both SOAP
     * and HTTP bindings generation logic embedded. First we parse all the
     * bindings to see if we have an existing binding. If we don't have one the
     * we will add it. Note there is no hard coding for HTTP or SOAP here, but
     * is there in the UI and we just consult the WTP model before adding it.
     *
     * @param definition the definition
     * @param bindings the bindings
     * @return the binding
     */
    public static Binding addBinding(Definition definition, Set<TemplateBinding> bindings) {
        Binding binding = null;

        if (definition.getBindings() != null) {
            Iterator iterator = definition.getBindings().values().iterator();
            while (iterator.hasNext()) {
                Object objBinding = iterator.next();
                if (objBinding != null && objBinding instanceof Binding) {
                    binding = (Binding) objBinding;
                    BindingGenerator bindingGenerator = new BindingGenerator(definition, binding);
                    for (TemplateBinding templBinding : bindings) {
                        // This is bad we are identifying the type
                        // of binding (ie if it is http or soap)
                        // by the name
                        if (StringUtils.containsIgnoreCase(binding.getQName().getLocalPart(),
                                templBinding.name())) {
                            if (bindingGenerator.getContentGenerator() == null) {
                                bindingGenerator.setOverwrite(true);
                                bindingGenerator.setContentGenerator(ContentGeneratorExtensionFactoryRegistry
                                        .getInstance().getGeneratorClassFromName(templBinding.name()));

                            }
                            bindingGenerator.generateBinding();

                        }
                    }

                }
            }
        }

        if (binding == null) {
            binding = WSDLFactory.eINSTANCE.createBinding();
            binding.setQName(
                    new QName(definition.getTargetNamespace(), ServiceTemplateConstants.DEFAULT_BINDING_NAME));
            binding.setEnclosingDefinition(definition);
            definition.addBinding(binding);
            BindingGenerator bindingGenerator = new BindingGenerator(definition, binding);
            bindingGenerator.generateBinding();
        }
        return binding;
    }

    /**
     * Creates an element definition with the given element name. The parent
     * type of this definition would be the base element name parameter and the
     * name space is the base element name space. THe definition is derived from
     * the part and the anonymous type is also created based on the part. This
     * API also makes sure that the parent type is imported before usage.
     *
     * @param elementName the element name
     * @param part the part
     * @param baseElementName the base element name
     * @param baseElementNameSpace the base element name space
     * @param typeFolding the type folding
     * @param targetNameSpace the target name space
     * @return the xSD complex type definition
     */
    public static XSDComplexTypeDefinition createXSDElementDefinition(String elementName, Part part,
            String baseElementName, String baseElementNameSpace, boolean typeFolding, String targetNameSpace) {
        XSDElementDeclaration elementDef = XSDComponentHelper.createAnonymousXSDElementDefinition(elementName,
                part);

        XSDComplexTypeDefinition complexType = XSDFactory.eINSTANCE.createXSDComplexTypeDefinition();
        complexType.setName(StringUtils.capitalize(elementName));
        complexType.setTargetNamespace(part.getEnclosingDefinition().getTargetNamespace());

        XSDParticle newXSDParticle = XSDFactory.eINSTANCE.createXSDParticle();
        XSDModelGroup newXSDModelGroup = XSDFactory.eINSTANCE.createXSDModelGroup();
        newXSDModelGroup.setCompositor(XSDCompositor.SEQUENCE_LITERAL);
        newXSDParticle.setContent(newXSDModelGroup);
        complexType.setContent(newXSDParticle);

        elementDef.setTypeDefinition(complexType);
        XSDComplexTypeDefinition complexTypeDefition = XSDComponentHelper
                .createXSDComplexTypeDefiniion(complexType.getName(), part);

        XSDComplexTypeDefinition restriction = XSDFactory.eINSTANCE.createXSDComplexTypeDefinition();

        if (!StringUtils.isEmpty(baseElementName) && !StringUtils.isEmpty(baseElementNameSpace)) {
            if (!typeFolding)
                restriction.setName(
                        TypeLibraryUIActivator.getPrefix(complexTypeDefition.getSchema(), baseElementNameSpace)
                                + baseElementName);
            else
                restriction
                        .setName(TypeLibraryUIActivator.getPrefix(complexTypeDefition.getSchema(), targetNameSpace)
                                + baseElementName);
            complexTypeDefition.setDerivationMethod(XSDDerivationMethod.EXTENSION_LITERAL);
            complexTypeDefition.setBaseTypeDefinition(restriction);
        }
        TypeLibraryUIActivator.addDocumentation(complexTypeDefition, "Document goes here");
        return complexTypeDefition;
    }

    /**
     * Computes the dependency of the parameter library type and in line the
     * WSDL with the computed types. Duplicate types will be ignored. This is
     * more a Wrapper over the method
     *
     * @param libraryType the library type
     * @param definition the definition
     * @param typeFolding the type folding
     * @throws Exception the exception
     * @see WTPTypeLibUtil#inlineType(LibraryType, Definition, boolean, boolean)
     */
    public static void inlineTypesInWSDL(LibraryType libraryType, Definition definition, boolean typeFolding)
            throws Exception {
        ArrayList<LibraryType> librarylist = new ArrayList<LibraryType>();
        librarylist.add(libraryType);
        for (LibraryType loopLibraryType : SOAGlobalRegistryAdapter.getInstance().getGlobalRegistry()
                .getDependentParentTypeFiles(libraryType)) {
            librarylist.add(loopLibraryType);
        }
        for (LibraryType selectedType : librarylist) {
            WTPTypeLibUtil.inlineType(selectedType, definition, true, typeFolding);
        }
    }

    private static void addImportDirective(XSDTypeDefinition typeDefinition, String libElementNamespace) {
        if (!StringUtil.broadEquals(typeDefinition.getSchema().getTargetNamespace(), libElementNamespace)
                && !importExists(typeDefinition.getSchema(), libElementNamespace)) {
            XSDImport xsdSchemaDirective = XSDFactory.eINSTANCE.createXSDImport();
            xsdSchemaDirective.setNamespace(libElementNamespace);
            typeDefinition.getSchema().getContents().add(0, xsdSchemaDirective);
        }
    }

    private static boolean importExists(XSDSchema schema, String libElementNamespace) {
        for (Iterator i = schema.getContents().iterator(); i.hasNext();) {
            Object o = i.next();
            if (o instanceof XSDImport) {
                if (StringUtil.broadEquals(((XSDImport) o).getNamespace(), libElementNamespace)) {
                    return true;
                }
            }
        }
        return false;
    }

}