/**
* 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.yoko.tools.processors.idl;
import javax.wsdl.Binding;
import javax.wsdl.BindingFault;
import javax.wsdl.BindingInput;
import javax.wsdl.BindingOperation;
import javax.wsdl.BindingOutput;
import javax.wsdl.Definition;
import javax.wsdl.Fault;
import javax.wsdl.Input;
import javax.wsdl.Message;
import javax.wsdl.Operation;
import javax.wsdl.Output;
import javax.wsdl.Part;
import javax.wsdl.PortType;
import javax.wsdl.WSDLException;
import javax.wsdl.extensions.ExtensionRegistry;
import javax.xml.namespace.QName;
import antlr.collections.AST;
import org.apache.schemas.yoko.bindings.corba.ArgType;
import org.apache.schemas.yoko.bindings.corba.OperationType;
import org.apache.schemas.yoko.bindings.corba.RaisesType;
import org.apache.schemas.yoko.bindings.corba.TypeMappingType;
import org.apache.ws.commons.schema.XmlSchema;
import org.apache.ws.commons.schema.XmlSchemaCollection;
import org.apache.ws.commons.schema.XmlSchemaComplexType;
import org.apache.ws.commons.schema.XmlSchemaElement;
import org.apache.ws.commons.schema.XmlSchemaSequence;
import org.apache.ws.commons.schema.XmlSchemaType;
import org.apache.yoko.wsdl.CorbaConstants;
import org.apache.yoko.wsdl.CorbaTypeImpl;
public class OperationVisitor extends VisitorBase {
private static final String REQUEST_SUFFIX = "Request";
private static final String RESPONSE_SUFFIX = "Response";
private static final String IN_PARAMETER = "inparameter";
private static final String OUT_PARAMETER = "outparameter";
private static final String INOUT_PARAMETER = "inoutparameter";
private static final String RETURN_PARAMETER = "return";
private Definition definition;
private ExtensionRegistry extReg;
private PortType portType;
private Binding binding;
private Message inputMsg;
private Message outputMsg;
private Part inputPart;
private Part outputPart;
private OperationType corbaOperation;
public OperationVisitor(Scope scope,
XmlSchemaCollection xmlSchemas,
XmlSchema xmlSchema,
TypeMappingType typeMapRef,
Definition wsdlDefinition,
PortType wsdlPortType,
Binding wsdlBinding) {
super(scope, xmlSchemas, xmlSchema, typeMapRef);
definition = wsdlDefinition;
extReg = definition.getExtensionRegistry();
portType = wsdlPortType;
binding = wsdlBinding;
}
public static boolean accept(Scope scope, XmlSchemaCollection schemas, XmlSchema schema,
TypeMappingType typeMap, AST node) {
boolean result = false;
AST node2 = node.getFirstChild();
if (node2.getType() == IDLTokenTypes.LITERAL_oneway) {
result = true;
} else {
int type = node2.getType();
result =
type == IDLTokenTypes.LITERAL_void
|| PrimitiveTypesVisitor.accept(node2)
|| StringVisitor.accept(node2)
|| ScopedNameVisitor.accept(scope, schemas, schema, typeMap, node2)
|| ObjectReferenceVisitor.accept(node2);
}
return result;
}
public void visit(AST node) {
// <op_dcl> ::= [<op_attribute>] <op_type_spec>
// <identifier> <parameter_dcls>
// [<raises_expr>] [<context_expr>]
// <op_attribute> ::= "oneway"
// <op_type_spec> ::= <param_type_spec>
// | "void"
// <parameter_dcls> ::= "(" <param_dcl> {"," <param_dcl>}* ")"
// | "(" ")"
// <raises_expr> ::= "raises" "(" <scoped_name> {"," <scoped_name>}* ")"
// <context_expr> ::= "context" "(" <string_literal> {"," <string_literal>}* ")"
Operation operation = generateOperation(node.toString());
BindingOperation bindingOperation = generateBindingOperation(binding, operation);
XmlSchemaSequence inputWrappingSequence = new XmlSchemaSequence();
XmlSchemaElement inputElement = generateWrapper(new QName(schema.getTargetNamespace(),
operation.getName()),
inputWrappingSequence);
inputMsg = generateInputMessage(operation, bindingOperation);
inputPart = generateInputPart(inputMsg, inputElement);
// <op_attribute>
node = node.getFirstChild();
XmlSchemaSequence outputWrappingSequence = null;
XmlSchemaElement outputElement = null;
if (node != null && (node.getType() == IDLTokenTypes.LITERAL_oneway)) {
// oneway operations map to operations with only input message
// no outputMsg nor outputPart need be created
node = node.getNextSibling();
} else {
// normal operations map to request-response operations
// with input and output messages
outputWrappingSequence = new XmlSchemaSequence();
outputElement = generateWrapper(new QName(schema.getTargetNamespace(),
operation.getName() + RESPONSE_SUFFIX),
outputWrappingSequence);
outputMsg = generateOutputMessage(operation, bindingOperation);
outputPart = generateOutputPart(outputMsg, outputElement);
}
// <op_type_spec>
visitOpTypeSpec(node, outputWrappingSequence);
// <parameter_dcls>
node = TypesUtils.getCorbaTypeNameNode(node);
while (ParamDclVisitor.accept(node)) {
ParamDclVisitor visitor = new ParamDclVisitor(getScope(),
schemas,
schema,
typeMap,
inputWrappingSequence,
outputWrappingSequence,
corbaOperation);
// need to provide the wsdl definition so that object references can be
// constructed correctly
visitor.setWSDLDefinition(definition);
visitor.visit(node);
node = node.getNextSibling();
}
// <raises_expr>
if (node != null
&& node.getType() == IDLTokenTypes.LITERAL_raises) {
node = node.getFirstChild();
while (node != null) {
// ScopedNameVisitor visitor = new ScopedNameVisitor(schemas,
// schema,
// typeMap);
// visitor.visit(node);
// XmlSchemaType schemaType = visitor.getSchemaType();
// CorbaTypeImpl corbaType = visitor.getCorbaType();
createFaultMessage(node, operation, bindingOperation);
node = node.getNextSibling();
}
}
}
private Operation generateOperation(String name) {
Operation op = definition.createOperation();
op.setName(name);
op.setUndefined(false);
portType.addOperation(op);
return op;
}
private BindingOperation generateBindingOperation(Binding wsdlBinding, Operation op) {
BindingOperation bindingOperation = definition.createBindingOperation();
//OperationType operationType = null;
try {
corbaOperation = (OperationType)extReg.createExtension(BindingOperation.class,
CorbaConstants.NE_CORBA_OPERATION);
} catch (WSDLException ex) {
throw new RuntimeException(ex);
}
corbaOperation.setName(op.getName());
bindingOperation.addExtensibilityElement(corbaOperation);
bindingOperation.setOperation(op);
bindingOperation.setName(op.getName());
binding.addBindingOperation(bindingOperation);
return bindingOperation;
}
public Message generateInputMessage(Operation operation, BindingOperation bindingOperation) {
Message msg = definition.createMessage();
msg.setQName(new QName(definition.getTargetNamespace(), operation.getName()));
msg.setUndefined(false);
String inputName = operation.getName() + REQUEST_SUFFIX;
Input input = definition.createInput();
input.setName(inputName);
input.setMessage(msg);
BindingInput bindingInput = definition.createBindingInput();
bindingInput.setName(inputName);
bindingOperation.setBindingInput(bindingInput);
operation.setInput(input);
definition.addMessage(msg);
return msg;
}
public Message generateOutputMessage(Operation operation, BindingOperation bindingOperation) {
Message msg = definition.createMessage();
msg.setQName(new QName(definition.getTargetNamespace(),
operation.getName() + RESPONSE_SUFFIX));
msg.setUndefined(false);
String outputName = operation.getName() + RESPONSE_SUFFIX;
Output output = definition.createOutput();
output.setName(outputName);
output.setMessage(msg);
BindingOutput bindingOutput = definition.createBindingOutput();
bindingOutput.setName(outputName);
bindingOperation.setBindingOutput(bindingOutput);
operation.setOutput(output);
definition.addMessage(msg);
return msg;
}
private Part generateInputPart(Message inputMessage, XmlSchemaElement element) {
// message - part
Part part = definition.createPart();
part.setName(IN_PARAMETER);
part.setElementName(element.getQName());
inputMessage.addPart(part);
return part;
}
private Part generateOutputPart(Message outputMessage, XmlSchemaElement element) {
// message - part
Part part = definition.createPart();
part.setName(OUT_PARAMETER);
part.setElementName(element.getQName());
outputMessage.addPart(part);
return part;
}
/*-
* Build the Wrapped Document Style wrapping elements
* i.e. <xs:element name="...">
* <xs:complexType>
* <xs:sequence>
* ...
* </xs:sequence>
* </xs:complexType>
* </xs:element>
*/
private XmlSchemaElement generateWrapper(QName el, XmlSchemaSequence wrappingSequence) {
XmlSchemaComplexType schemaComplexType = new XmlSchemaComplexType(schema);
schemaComplexType.setParticle(wrappingSequence);
XmlSchemaElement wrappingSchemaElement = new XmlSchemaElement();
wrappingSchemaElement.setQName(el);
wrappingSchemaElement.setName(el.getLocalPart());
wrappingSchemaElement.setSchemaType(schemaComplexType);
schema.getElements().add(el, wrappingSchemaElement);
schema.getItems().add(wrappingSchemaElement);
return wrappingSchemaElement;
}
private XmlSchemaElement addElement(XmlSchemaSequence schemaSequence,
XmlSchemaType schemaType,
String name,
boolean isObjectReference) {
XmlSchemaElement element = new XmlSchemaElement();
element.setName(name);
// REVISIT: An object reference requires that we use a ref name. An element type produces
// a wsdltojava error.
if (isObjectReference) {
element.setRefName(schemaType.getQName());
} else {
element.setSchemaTypeName(schemaType.getQName());
}
schemaSequence.getItems().add(element);
return element;
}
private void visitOpTypeSpec(AST node, XmlSchemaSequence outputWrappingSequence) {
if (node.getType() == IDLTokenTypes.LITERAL_void) {
// nothing to do here, move along
return;
} else {
ParamTypeSpecVisitor visitor = new ParamTypeSpecVisitor(getScope(),
schemas,
schema,
typeMap,
definition);
visitor.visit(node);
XmlSchemaType schemaType = visitor.getSchemaType();
CorbaTypeImpl corbaType = visitor.getCorbaType();
boolean isObjectReference = false;
if (corbaType instanceof org.apache.schemas.yoko.bindings.corba.Object) {
isObjectReference = true;
}
addElement(outputWrappingSequence, schemaType, RETURN_PARAMETER, isObjectReference);
addCorbaReturn(corbaType, RETURN_PARAMETER);
}
}
private void addCorbaReturn(CorbaTypeImpl corbaType, String partName) {
ArgType param = new ArgType();
param.setName(partName);
param.setIdltype(corbaType.getQName());
corbaOperation.setReturn(param);
}
private void createFaultMessage(AST node,
Operation operation,
BindingOperation bindingOperation) {
String exceptionName = node.toString();
// message
Message faultMsg = definition.createMessage();
faultMsg.setQName(new QName(definition.getTargetNamespace(), exceptionName));
faultMsg.setUndefined(false);
// message - part
Part part = definition.createPart();
part.setName("exception");
// REVISIT: should be reading QName from exception XmlSchemaElement
// part.setElementName(element.getQName());
part.setElementName(new QName(definition.getTargetNamespace(), exceptionName));
faultMsg.addPart(part);
// porttype - operation - fault
Fault fault = definition.createFault();
fault.setMessage(faultMsg);
fault.setName(faultMsg.getQName().getLocalPart());
operation.addFault(fault);
// binding - operation - corba:operation - corba:raises
RaisesType raisesType = new RaisesType();
raisesType.setException(new QName(typeMap.getTargetNamespace(),
exceptionName));
corbaOperation.getRaises().add(raisesType);
// binding - operation - fault
BindingFault bindingFault = definition.createBindingFault();
bindingFault.setName(faultMsg.getQName().getLocalPart());
bindingOperation.addBindingFault(bindingFault);
definition.addMessage(faultMsg);
}
}