blob: 67f613bf0725a127e87a0e93f2607b506a034264 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2007 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.wsdl.internal.generator;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.namespace.QName;
import org.eclipse.wst.wsdl.Binding;
import org.eclipse.wst.wsdl.BindingFault;
import org.eclipse.wst.wsdl.BindingInput;
import org.eclipse.wst.wsdl.BindingOperation;
import org.eclipse.wst.wsdl.BindingOutput;
import org.eclipse.wst.wsdl.Definition;
import org.eclipse.wst.wsdl.ExtensibilityElement;
import org.eclipse.wst.wsdl.ExtensibleElement;
import org.eclipse.wst.wsdl.Fault;
import org.eclipse.wst.wsdl.Input;
import org.eclipse.wst.wsdl.Operation;
import org.eclipse.wst.wsdl.Output;
import org.eclipse.wst.wsdl.Port;
import org.eclipse.wst.wsdl.PortType;
import org.eclipse.wst.wsdl.Service;
import org.eclipse.wst.wsdl.WSDLFactory;
import org.eclipse.wst.wsdl.internal.generator.extension.ContentGeneratorExtensionFactoryRegistry;
/*
* Class used to generate the Binding and it's content. We look in the registry for
* appropriate ContentGenerator classes based on the existing Binding Content's namespace.
* Alternatively, users can pass in a namespace through the constructor to specify which
* namespace to use when searching the registry.
*
* The ContentGenerator may also be set manually by calling
* setContentGenerator(ContentGenerator).
*/
public class BindingGenerator extends BaseGenerator
{
private WSDLFactory factory = WSDLFactory.eINSTANCE;
private Binding binding;
/*
* When the constructor is used, automatically attempt to retrieve a proper
* ContentGenerator based on the Binding given. The ContentGenerator may
* be replaced by calling setContentGenerator(ContentGenerator).
*/
public BindingGenerator(Definition definition, Binding binding)
{
this.definition = definition;
this.binding = binding;
contentGenerator = getContentGenerator(binding);
}
/*
* When the constructor is used, automatically attempt to retrieve a proper
* ContentGenerator based on the namespace given. The ContentGenerator may
* be replaced by calling setContentGenerator(ContentGenerator).
*/
public BindingGenerator(Definition definition, Binding binding, String namespace)
{
this.definition = definition;
this.binding = binding;
contentGenerator = getContentGenerator(namespace);
}
public static ContentGenerator getContentGenerator(Binding binding)
{
if (binding == null)
{
return null;
}
/******************************************************
* Find the regeistered Content Generator for the Binding
******************************************************/
// Get BindingContent namespace
String namespace = null;
List eeList = binding.getEExtensibilityElements();
if (eeList.size() > 0)
{
ExtensibilityElement ee = (ExtensibilityElement)eeList.get(0);
// TODO: QName qName = ee.getElementType(); go get the namespace instead?
namespace = ee.getElement().getNamespaceURI();
return getContentGenerator(namespace);
}
return null;
}
public static ContentGenerator getContentGenerator(String namespace)
{
ContentGenerator contentGen = null;
if (namespace != null)
{
ContentGeneratorExtensionFactoryRegistry factoryRegistry = ContentGeneratorExtensionFactoryRegistry.getInstance();
contentGen = factoryRegistry.getGeneratorClassFromNamespace(namespace);
}
return contentGen;
}
private Binding createEmptyBinding(String localName)
{
Binding newBinding = WSDLFactory.eINSTANCE.createBinding();
newBinding.setQName(new QName(definition.getTargetNamespace(), localName));
newBinding.setEnclosingDefinition(definition);
definition.addBinding(newBinding);
return newBinding;
}
/*
* TODO: Scenario:
* 1)overwrite == false
* 2)BindingOperation with 1 input
* 3)Corresponding Operation (with same name) with 1 input and 1 output
* If we generate with overwrite == false, nothing is done. Thus, an
* output is not generated on the BindingOperation. This is because we
* search for existing Elements only at the level of BindingOperations.
* For example, if there is a corresponding BindingOperation with the same
* name as our Operation, leave it alone.... but since there is already
* a BindingOperation with the same name, we don't create a new BindingOperation.
*
* The correct implementation is reduce this granularity to the MessageReference
* level. The code is almost there except for how we generate the Binding element
* content. Look at BindingGenrator.generateBindingOperation() and
* SOAPContentGenerator.java and it's content generation method
* for a good place to start.
*
* For wtp RC1, We shall only look at the Operation level (as we do in the previous
* version).
*/
public Binding generateBinding()
{
try
{
// If Binding is null (No Binding was passed into the constructor), we create an empty Binding first.
if (binding == null)
{
binding = createEmptyBinding(getName());
}
if (getName() != null && !binding.getQName().getLocalPart().equals(getName()))
{
binding.setQName(new QName(binding.getQName().getNamespaceURI(), getName()));
}
if (getRefName() != null)
{
PortType portType = getPortType();
binding.setEPortType(portType);
if (portType == null)
{
//The model doesn't reconile with it's Element properly when we're setting a null for it's PortType
binding.getElement().setAttribute("type", "");
}
}
List bindingOperations = binding.getEBindingOperations();
PortType portType = binding.getEPortType();
if (!getOverwrite())
{
// Don't Overwrite
if (portType == null)
{
return binding;
}
else
{
addRequiredNamespaces(binding);
List operations = portType.getOperations();
/*******************************************************************************
* Determine which Operations require new a new corresponding BindingOperations
*******************************************************************************/
List newBindingOpsNeeded = new ArrayList();
for (int index = 0; index < operations.size(); index++)
{
Operation operation = (Operation)operations.get(index);
boolean foundMatch = false;
Iterator bindingOperationsIt = bindingOperations.iterator();
while (bindingOperationsIt.hasNext())
{
BindingOperation bindingOperation = (BindingOperation)bindingOperationsIt.next();
if (namesEqual(bindingOperation.getName(), operation.getName()))
{
foundMatch = true;
break;
}
}
if (!foundMatch)
{
newBindingOpsNeeded.add(operation);
}
}
// newBindingOpsNeeded is the List of Operations needing new corresponding
// BindingOperation's
List newBindingOps = createNewBindingOperations(newBindingOpsNeeded);
// Generate the contents of the new BindingOperation's
Iterator newBindingOpsIt = newBindingOps.iterator();
while (newBindingOpsIt.hasNext())
{
BindingOperation newBindingOp = (BindingOperation)newBindingOpsIt.next();
generateBindingOperation(newBindingOp);
generateBindingOperationContent(newBindingOp);
}
}
generateBindingContent(binding);
}
else
{
// Overwrite
if (portType == null)
{
// We need to blow away everything under the Binding. No PortType associated with this Binding
bindingOperations.clear();
return binding;
}
else
{
addRequiredNamespaces(binding);
List operations = portType.getOperations();
/******************************************************
* Compare the Operations
******************************************************/
// Remove any BindingOperations which are no longer used
for (int index = 0; index < bindingOperations.size(); index++)
{
BindingOperation bindingOperation = (BindingOperation)bindingOperations.get(index);
boolean foundMatch = false;
Iterator operationsIt = operations.iterator();
while (operationsIt.hasNext())
{
Operation operation = (Operation)operationsIt.next();
if (namesEqual(bindingOperation.getName(), operation.getName()))
{
foundMatch = true;
break;
}
}
if (!foundMatch)
{
// We need to remove this BindingFault from the bindingFaults List
bindingOperations.remove(index);
index--;
}
}
// Remove any Operations which already exists in bindingOperations. What we
// have left are the Operations which needs newly created BindingOperations
List bindingOperationsNeeded = new ArrayList();
for (int index = 0; index < operations.size(); index++)
{
Operation operation = (Operation)operations.get(index);
boolean foundMatch = false;
Iterator bindingOperationsIt = bindingOperations.iterator();
while (bindingOperationsIt.hasNext())
{
BindingOperation bindingOperation = (BindingOperation)bindingOperationsIt.next();
if (namesEqual(bindingOperation.getName(), operation.getName()))
{
foundMatch = true;
break;
}
}
if (!foundMatch)
{
// We need to remove this BindingFault from the bindingFaults List
bindingOperationsNeeded.add(operation); // Store the actual Operation
}
}
// Create required BindingOperations
createNewBindingOperations(bindingOperationsNeeded);
/******************************************************
* Process the contents of the Operations
******************************************************/
Iterator bindingOperationsIt = binding.getEBindingOperations().iterator();
while (bindingOperationsIt.hasNext())
{
generateBindingOperation((BindingOperation)bindingOperationsIt.next());
}
generateBindingContent(binding);
return binding;
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
private List createNewBindingOperations(List operations)
{
List newBindingOps = new ArrayList();
Iterator neededBindingOperationsIt = operations.iterator();
while (neededBindingOperationsIt.hasNext())
{
Operation operation = (Operation)neededBindingOperationsIt.next();
BindingOperation newBindingOperation = factory.createBindingOperation();
newBindingOperation.setEOperation(operation);
newBindingOperation.setName(operation.getName());
binding.addBindingOperation(newBindingOperation);
newBindingOps.add(newBindingOperation);
}
return newBindingOps;
}
private void generateBindingOperation(BindingOperation bindingOperation)
{
BindingInput bindingInput = bindingOperation.getEBindingInput();
BindingOutput bindingOutput = bindingOperation.getEBindingOutput();
List bindingFaults = bindingOperation.getEBindingFaults();
Operation operation = bindingOperation.getEOperation();
Input input = operation.getEInput();
Output output = operation.getEOutput();
List faults = operation.getEFaults();
/******************************************************
* Compare the Operation names
******************************************************/
if (!namesEqual(bindingOperation.getName(), operation.getName()))
{
bindingOperation.setName(operation.getName());
}
/******************************************************
* Compare the Output
******************************************************/
if (output == null)
{
bindingOperation.setBindingOutput(null);
}
else
{
// Create BindingOutput if necessary
if (bindingOutput == null)
{
BindingOutput newBindingOutput = factory.createBindingOutput();
newBindingOutput.setEOutput(output);
newBindingOutput.setName(output.getName());
bindingOperation.setBindingOutput(newBindingOutput);
}
else
{
// Compare the Output names
if (!namesEqual(bindingOutput.getName(), output.getName()))
{
bindingOutput.setName(output.getName());
}
}
}
generateBindingOutputContent(bindingOperation.getEBindingOutput());
/******************************************************
* Compare the Input
******************************************************/
if (input == null)
{
bindingOperation.setBindingInput(null);
}
else
{
// Create BindingInput if necessary
if (bindingInput == null)
{
BindingInput newBindingInput = factory.createBindingInput();
newBindingInput.setEInput(input);
newBindingInput.setName(input.getName());
bindingOperation.setBindingInput(newBindingInput);
}
else
{
// Compare the Input names
if (!namesEqual(bindingInput.getName(), input.getName()))
{
bindingInput.setName(input.getName());
}
}
}
generateBindingInputContent(bindingOperation.getEBindingInput());
/******************************************************
* Compare the Faults
******************************************************/
// Remove any BindingFaults which are no longer used
for (int index = 0; index < bindingFaults.size(); index++)
{
BindingFault bindingFault = (BindingFault)bindingFaults.get(index);
boolean foundMatch = false;
Iterator faultsIt = faults.iterator();
while (faultsIt.hasNext())
{
Fault fault = (Fault)faultsIt.next();
if (namesEqual(bindingFault.getName(), fault.getName()))
{
foundMatch = true;
break;
}
}
if (!foundMatch)
{
// We need to remove this BindingFault from the bindingFaults List
bindingFaults.remove(index);
index--;
}
}
// Remove any Faults which already exists in bindingFaults. What we
// have left are the Faults which needs newly created BindingFaults
List bindingFaultsNeeded = new ArrayList();
for (int index = 0; index < faults.size(); index++)
{
Fault fault = (Fault)faults.get(index);
boolean foundMatch = false;
Iterator bindingFaultsIt = bindingFaults.iterator();
while (bindingFaultsIt.hasNext())
{
BindingFault bindingFault = (BindingFault)bindingFaultsIt.next();
if (namesEqual(bindingFault.getName(), fault.getName()))
{
foundMatch = true;
break;
}
}
if (!foundMatch)
{
// We need to remove this BindingFault from the bindingFaults List
bindingFaultsNeeded.add(fault);
}
}
// bindingFaultsNeeded contains the needed BindingFault's we need to create
Iterator neededBindingFaultsIt = bindingFaultsNeeded.iterator();
while (neededBindingFaultsIt.hasNext())
{
Fault fault = (Fault)neededBindingFaultsIt.next();
BindingFault newBindingFault = factory.createBindingFault();
newBindingFault.setEFault(fault);
newBindingFault.setName(fault.getName());
bindingOperation.addBindingFault(newBindingFault);
}
// Create the contents for each BindingFault
Iterator faultContentIt = bindingOperation.getEBindingFaults().iterator();
while (faultContentIt.hasNext())
{
BindingFault bindingFault = (BindingFault)faultContentIt.next();
generateBindingFaultContent(bindingFault);
}
generateBindingOperationContent(bindingOperation);
}
private boolean namesEqual(String name1, String name2)
{
boolean match = false;
if (name1 != null ^ name2 != null)
{
// one is null
match = false;
}
else if (name1 != null && name2 != null)
{
// neither is null
match = name1.equals(name2);
}
else
{
// both are null
match = true;
}
return match;
}
protected void generateBindingContent(Binding binding)
{
if (contentGenerator != null)
{
if (getOverwrite() || binding.getEExtensibilityElements().size() == 0)
{
contentGenerator.generateBindingContent(binding, (PortType)binding.getEPortType());
}
}
else
{
removeExtensibilityElements(binding);
}
}
protected void generateBindingOperationContent(BindingOperation bindingOperation)
{
if (bindingOperation != null && contentGenerator != null)
{
contentGenerator.generateBindingOperationContent(bindingOperation, bindingOperation.getEOperation());
}
else
{
removeExtensibilityElements(bindingOperation);
}
}
protected void generateBindingInputContent(BindingInput bindingInput)
{
if (bindingInput != null && contentGenerator != null)
{
contentGenerator.generateBindingInputContent(bindingInput, bindingInput.getEInput());
}
else
{
removeExtensibilityElements(bindingInput);
}
}
protected void generateBindingOutputContent(BindingOutput bindingOutput)
{
if (bindingOutput != null && contentGenerator != null)
{
contentGenerator.generateBindingOutputContent(bindingOutput, bindingOutput.getEOutput());
}
else
{
removeExtensibilityElements(bindingOutput);
}
}
protected void generateBindingFaultContent(BindingFault bindingFault)
{
if (bindingFault != null && contentGenerator != null)
{
contentGenerator.generateBindingFaultContent(bindingFault, bindingFault.getEFault());
}
else
{
removeExtensibilityElements(bindingFault);
}
}
private void removeExtensibilityElements(ExtensibleElement ee)
{
if (ee != null)
{
ee.getEExtensibilityElements().clear();
}
}
/*
* Generate Port Content for all Ports with a reference to the Binding
* which was passed in through the constructor (or a reference to the
* newly created Binding).
*/
public void generatePortContent()
{
if (binding != null && contentGenerator != null)
{
List portsToUpdate = new ArrayList();
Iterator servicesIt = binding.getEnclosingDefinition().getEServices().iterator();
while (servicesIt.hasNext())
{
Service service = (Service)servicesIt.next();
Iterator portsIt = service.getEPorts().iterator();
while (portsIt.hasNext())
{
Port port = (Port)portsIt.next();
if (binding.equals(port.getEBinding()))
{
// Found a match
portsToUpdate.add(port);
}
}
}
Iterator portsToUpdateIt = portsToUpdate.iterator();
while (portsToUpdateIt.hasNext())
{
contentGenerator.generatePortContent((Port)portsToUpdateIt.next());
}
}
}
/*
* methods addRequiredNamespaces() and computeUniquePrefix() are used to add necessary
* namespaces
*
* TODO:
* Does this belong here? This is copied from wsdl.ui. Can we sync up in some way?
*/
protected void addRequiredNamespaces(Binding binding)
{
if (contentGenerator != null)
{
String[] namespaceNames = contentGenerator.getRequiredNamespaces();
String[] preferredPrefixes = new String [namespaceNames.length];
for (int index = 0; index < namespaceNames.length; index++)
{
preferredPrefixes[index] = contentGenerator.getPreferredNamespacePrefix(namespaceNames[index]);
}
Map map = binding.getEnclosingDefinition().getNamespaces();
for (int i = 0; i < namespaceNames.length; i++)
{
String namespace = namespaceNames[i];
if (!map.containsValue(namespace))
{
String prefix = (i < preferredPrefixes.length) ? preferredPrefixes[i] : "p0";
if (map.containsKey(prefix))
{
prefix = computeUniquePrefix("p", map);
}
binding.getEnclosingDefinition().addNamespace(prefix, namespace);
}
}
}
}
private String computeUniquePrefix(String base, Map table)
{
int i = 0;
String prefix = base;
while (true)
{
if (!table.containsKey(prefix))
{
break;
}
else
{
prefix = base + i;
i++;
}
}
return prefix;
}
private PortType getPortType()
{
if (getRefName().equals(""))
{
// Means we should set the PortType to Unspecified
return null;
}
if (getRefName() != null)
{
Iterator portTypeIt = definition.getEPortTypes().iterator();
while (portTypeIt.hasNext())
{
PortType pt = (PortType)portTypeIt.next();
List prefixedNames = getPrefixedNames(pt);
if (prefixedNames.contains(getRefName()))
{
return pt;
}
}
}
return binding.getEPortType();
}
private List getPrefixedNames(PortType portType)
{
List prefixedNames = new ArrayList();
String currentPortTypeName = portType.getQName().getLocalPart();
String currentNamespace = portType.getQName().getNamespaceURI();
Map namespaceMap = definition.getNamespaces();
Iterator keys = namespaceMap.keySet().iterator();
while (keys.hasNext())
{
Object key = keys.next();
Object value = namespaceMap.get(key);
if (currentNamespace.equals(value))
{
// Found a match. Add to our list
prefixedNames.add(key + ":" + currentPortTypeName);
}
}
return prefixedNames;
}
}