/**
* 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.tools.corba.processors.idl;
import java.util.Iterator;
import java.util.List;
import javax.wsdl.Definition;
import javax.xml.namespace.QName;
import antlr.collections.AST;
import org.apache.cxf.binding.corba.wsdl.CorbaType;
import org.apache.cxf.binding.corba.wsdl.MemberType;
import org.apache.cxf.binding.corba.wsdl.Struct;
import org.apache.cxf.tools.corba.common.ReferenceConstants;
import org.apache.ws.commons.schema.XmlSchema;
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;
public class StructVisitor extends VisitorBase {
public StructVisitor(Scope scope,
Definition defn,
XmlSchema schemaRef,
WSDLASTVisitor wsdlVisitor) {
super(scope, defn, schemaRef, wsdlVisitor);
}
public static boolean accept(AST node) {
return node.getType() == IDLTokenTypes.LITERAL_struct;
}
public void visit(AST node) {
// <struct_type> ::= "struct" <identifier> "{" <member_list> "}"
// <member_list> ::= <member>+
// <member> ::= <type_spec> <declarators> ";"
AST identifierNode = node.getFirstChild();
// Check if its a forward declaration
if (identifierNode.getFirstChild() == null && identifierNode.getNextSibling() == null) {
visitForwardDeclaredStruct(identifierNode);
} else {
visitDeclaredStruct(identifierNode);
}
}
public void visitDeclaredStruct(AST identifierNode) {
Scope structScope = new Scope(getScope(), identifierNode);
// xmlschema:struct
XmlSchemaComplexType complexType = new XmlSchemaComplexType(schema, true);
complexType.setName(mapper.mapToQName(structScope));
XmlSchemaSequence sequence = new XmlSchemaSequence();
complexType.setParticle(sequence);
// corba:struct
Struct struct = new Struct();
struct.setQName(new QName(typeMap.getTargetNamespace(), structScope.toString()));
struct.setType(complexType.getQName());
struct.setRepositoryID(structScope.toIDLRepositoryID());
boolean recursiveAdd = addRecursiveScopedName(identifierNode);
// struct members
visitStructMembers(identifierNode, struct, sequence, structScope);
if (recursiveAdd) {
removeRecursiveScopedName(identifierNode);
}
// add corbaType
typeMap.getStructOrExceptionOrUnion().add(struct);
// REVISIT: are there assignment needed?
setSchemaType(complexType);
setCorbaType(struct);
// Need to check if the struct was forward declared
processForwardStructActions(structScope);
// Once we've finished declaring the struct, we should make sure it has been removed from
// the list of scopedNames so that we inidicate that is no longer simply forward declared.
scopedNames.remove(structScope);
}
private void visitStructMembers(AST identifierNode, Struct struct,
XmlSchemaSequence sequence,
Scope structScope) {
AST memberTypeNode = identifierNode.getNextSibling();
while (memberTypeNode != null) {
AST memberNode = TypesUtils.getCorbaTypeNameNode(memberTypeNode);
XmlSchemaType schemaType = null;
CorbaType corbaType = null;
Scope fqName = null;
try {
TypesVisitor visitor = new TypesVisitor(structScope,
definition,
schema,
wsdlVisitor,
null);
visitor.visit(memberTypeNode);
schemaType = visitor.getSchemaType();
corbaType = visitor.getCorbaType();
fqName = visitor.getFullyQualifiedName();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
// Handle multiple struct member declarators
// <declarators> :== <declarator> { "," <declarator> }*
//
// A multiple declarator must be an identifier (i.e. of type IDENT)
// and cannot be a previous declared (or forward declared) type
// (hence the ScopedNameVisitor.accept() call).
while (memberNode != null
&& memberNode.getType() == IDLTokenTypes.IDENT
&& !ScopedNameVisitor.accept(structScope, definition, schema, memberNode, wsdlVisitor, true)) {
XmlSchemaType memberSchemaType = schemaType;
CorbaType memberCorbaType = corbaType;
// needed for anonymous arrays in structs
if (ArrayVisitor.accept(memberNode)) {
Scope anonScope = new Scope(structScope,
TypesUtils.getCorbaTypeNameNode(memberTypeNode));
ArrayVisitor arrayVisitor = new ArrayVisitor(anonScope,
definition,
schema,
wsdlVisitor,
null,
fqName);
arrayVisitor.setSchemaType(schemaType);
arrayVisitor.setCorbaType(corbaType);
arrayVisitor.visit(memberNode);
memberSchemaType = arrayVisitor.getSchemaType();
memberCorbaType = arrayVisitor.getCorbaType();
fqName = arrayVisitor.getFullyQualifiedName();
}
XmlSchemaElement member =
createXmlSchemaElement(memberNode, memberSchemaType, fqName);
sequence.getItems().add(member);
MemberType memberType =
createMemberType(memberNode, memberCorbaType, fqName);
struct.getMember().add(memberType);
memberNode = memberNode.getNextSibling();
}
memberTypeNode = memberNode;
}
}
private XmlSchemaElement createXmlSchemaElement(AST memberNode,
XmlSchemaType schemaType,
Scope fqName) {
// xmlschema:member
XmlSchemaElement member = new XmlSchemaElement(schema, false);
String memberName = memberNode.toString();
member.setName(memberName);
member.setSchemaType(schemaType);
if (schemaType != null) {
member.setSchemaTypeName(schemaType.getQName());
if (schemaType.getQName().equals(ReferenceConstants.WSADDRESSING_TYPE)) {
member.setNillable(true);
}
} else {
wsdlVisitor.getDeferredActions().
add(fqName, new StructDeferredAction(member));
}
return member;
}
private MemberType createMemberType(AST memberNode,
CorbaType corbaType,
Scope fqName) {
// corba:member
String memberName = memberNode.toString();
MemberType memberType = new MemberType();
memberType.setName(memberName);
if (corbaType != null) {
memberType.setIdltype(corbaType.getQName());
} else {
wsdlVisitor.getDeferredActions().
add(fqName, new StructDeferredAction(memberType));
}
return memberType;
}
private void visitForwardDeclaredStruct(AST identifierNode) {
String structName = identifierNode.toString();
Scope structScope = new Scope(getScope(), structName);
ScopeNameCollection scopedNames = wsdlVisitor.getScopedNames();
if (scopedNames.getScope(structScope) == null) {
scopedNames.add(structScope);
}
}
// Process any actions that were defered for a forward declared struct
private void processForwardStructActions(Scope structScope) {
if (wsdlVisitor.getDeferredActions() != null) {
DeferredActionCollection deferredActions = wsdlVisitor.getDeferredActions();
List<DeferredAction> list = deferredActions.getActions(structScope);
if ((list != null) && !list.isEmpty()) {
XmlSchemaType stype = getSchemaType();
CorbaType ctype = getCorbaType();
Iterator<DeferredAction> iterator = list.iterator();
while (iterator.hasNext()) {
SchemaDeferredAction action = (SchemaDeferredAction)iterator.next();
action.execute(stype, ctype);
}
iterator = list.iterator();
while (iterator.hasNext()) {
iterator.next();
iterator.remove();
}
}
}
}
private boolean addRecursiveScopedName(AST identifierNode) {
String structName = identifierNode.toString();
Scope structScope = new Scope(getScope(), structName);
ScopeNameCollection scopedNames = wsdlVisitor.getScopedNames();
if (scopedNames.getScope(structScope) == null) {
scopedNames.add(structScope);
return true;
}
return false;
}
private void removeRecursiveScopedName(AST identifierNode) {
String structName = identifierNode.toString();
Scope structScope = new Scope(getScope(), structName);
ScopeNameCollection scopedNames = wsdlVisitor.getScopedNames();
scopedNames.remove(structScope);
}
}