blob: c3cf1506e1ecea126abc82a1633a3be14f9e91b1 [file] [log] [blame]
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) {
String name = localName;
if (localName == null) {
name = "";
}
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 (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;
}
}