/* * Copyright 2013 Guidewire Software, Inc. */ package gw.internal.xml.ws.server; import gw.config.CommonServices; import gw.internal.schema.gw.xsd.w3c.wsdl.Definitions; import gw.internal.schema.gw.xsd.w3c.wsdl.anonymous.elements.TBindingOperation_Fault; import gw.internal.schema.gw.xsd.w3c.wsdl.anonymous.elements.TBindingOperation_Input; import gw.internal.schema.gw.xsd.w3c.wsdl.anonymous.elements.TBindingOperation_Output; import gw.internal.schema.gw.xsd.w3c.wsdl.anonymous.elements.TBinding_Operation; import gw.internal.schema.gw.xsd.w3c.wsdl.anonymous.elements.TDefinitions_Binding; import gw.internal.schema.gw.xsd.w3c.wsdl.anonymous.elements.TDefinitions_Message; import gw.internal.schema.gw.xsd.w3c.wsdl.anonymous.elements.TDefinitions_PortType; import gw.internal.schema.gw.xsd.w3c.wsdl.anonymous.elements.TDefinitions_Service; import gw.internal.schema.gw.xsd.w3c.wsdl.anonymous.elements.TDefinitions_Types; import gw.internal.schema.gw.xsd.w3c.wsdl.anonymous.elements.TDocumented_Documentation; import gw.internal.schema.gw.xsd.w3c.wsdl.anonymous.elements.TMessage_Part; import gw.internal.schema.gw.xsd.w3c.wsdl.anonymous.elements.TOperation_Fault; import gw.internal.schema.gw.xsd.w3c.wsdl.anonymous.elements.TOperation_Input; import gw.internal.schema.gw.xsd.w3c.wsdl.anonymous.elements.TOperation_Output; import gw.internal.schema.gw.xsd.w3c.wsdl.anonymous.elements.TPortType_Operation; import gw.internal.schema.gw.xsd.w3c.wsdl.anonymous.elements.TService_Port; import gw.internal.schema.gw.xsd.w3c.xmlschema.Element; import gw.internal.schema.gw.xsd.w3c.xmlschema.Schema; import gw.internal.schema.gw.xsd.w3c.xmlschema.Sequence; import gw.internal.schema.gw.xsd.w3c.xmlschema.anonymous.elements.ExplicitGroup_Element; import gw.internal.schema.gw.xsd.w3c.xmlschema.anonymous.elements.TopLevelElement_ComplexType; import gw.internal.schema.gw.xsd.w3c.xmlschema.enums.FormChoice; import gw.internal.xml.IXmlLoggerFactory; import gw.internal.xml.config.XmlServices; import gw.internal.xml.ws.server.marshal.MarshalInfo; import gw.internal.xml.XmlSchemaAccessImpl; import gw.internal.xml.ws.server.marshal.ClassBasedMarshalInfo; import gw.internal.xml.ws.server.marshal.XmlMarshaller; import gw.lang.function.Function2; import gw.lang.function.Function3; import gw.lang.reflect.IAnnotationInfo; import gw.lang.reflect.IExceptionInfo; import gw.lang.reflect.IMethodInfo; import gw.lang.reflect.IParameterInfo; import gw.lang.reflect.IType; import gw.lang.reflect.TypeSystem; import gw.lang.reflect.gs.IGosuClassTypeInfo; import gw.lang.reflect.java.JavaTypes; import gw.util.GosuExceptionUtil; import gw.util.concurrent.LockingLazyVar; import gw.xml.XmlNamespace; import gw.xml.XmlSchemaAccess; import gw.xml.XmlSerializationOptions; import gw.xml.ws.WebServiceException; import gw.xml.ws.WsiAuthenticationException; import java.net.URI; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import javax.xml.namespace.QName; public class WsiUtilities { public static final LockingLazyVar<IType> WSI_WEB_SERVICE_ANNOTATION_TYPE = new LockingLazyVar<IType>() { @Override protected IType init() { return TypeSystem.getByFullName("gw.xml.ws.annotation.WsiWebService"); } }; public static final LockingLazyVar<IType> WSI_SCHEMA_TRANSFORM_ANNOTATION_TYPE = new LockingLazyVar<IType>( TypeSystem.getGlobalLock() ) { @Override protected IType init() { return TypeSystem.getByFullName( "gw.xml.ws.annotation.WsiSchemaTransform" ); } }; public static final LockingLazyVar<IType> WEB_METHOD_ANNOTATION_TYPE = new LockingLazyVar<IType>( TypeSystem.getGlobalLock() ) { @Override protected IType init() { return TypeSystem.getByFullName( "gw.xml.ws.annotation.WsiWebMethod" ); } }; public static final LockingLazyVar<IType> WSI_ADDITIONAL_SCHEMAS_ANNOTATION_TYPE = new LockingLazyVar<IType>() { @Override protected IType init() { return TypeSystem.getByFullName( "gw.xml.ws.annotation.WsiAdditionalSchemas" ); } }; private static final LockingLazyVar<IType> WSI_INVOCATION_CONTEXT_TYPE = new LockingLazyVar<IType>( TypeSystem.getGlobalLock() ) { @Override protected IType init() { return TypeSystem.getByFullName( "gw.xml.ws.WsiInvocationContext" ); } }; private static final LockingLazyVar<IType> WSI_EXPOSE_ENUM_AS_STRING_ANNOTATION_TYPE = new LockingLazyVar<IType>( TypeSystem.getGlobalLock() ) { @Override protected IType init() { return TypeSystem.getByFullName( "gw.xml.ws.annotation.WsiExposeEnumAsString" ); } }; private static final Comparator<IType> COMPARATOR = new Comparator<IType>() { @Override public int compare(IType o1, IType o2) { return o1.getRelativeName().compareTo(o2.getRelativeName()); } }; public static final LockingLazyVar<Collection<IType>> EXCEPTIONS_THROWN_BY_INFRASTRUCTURE = new LockingLazyVar<Collection<IType>>( TypeSystem.getGlobalLock() ) { @Override protected Collection<IType> init() { TreeSet<IType> rtn = new TreeSet<IType>(COMPARATOR); rtn.add(TypeSystem.get(WsiAuthenticationException.class)); return rtn; } }; public static WsiServiceInfo generateWsdl( IType type, String requestURL, String xsdRootURL ) { return generateWsdl( type, requestURL, xsdRootURL, WebservicesServletBase.getDefaultLocalWebservicesServlet() ); } public static WsiServiceInfo generateWsdl( IType type, String requestURL, String xsdRootURL, WebservicesServletBase servlet ) { if (xsdRootURL == null) { xsdRootURL = ""; } IType wsiInvocationContextType = WSI_INVOCATION_CONTEXT_TYPE.get(); Definitions wsdl = new Definitions(); wsdl.setComment( "Generated WSDL for " + type.getName() + " web service" ); try { Set<IType> exposeEnumAsStringTypes = new HashSet<IType>(); for ( IAnnotationInfo wsiExposeEnumAsStringAnnotationInfo : type.getTypeInfo().getAnnotationsOfType( WSI_EXPOSE_ENUM_AS_STRING_ANNOTATION_TYPE.get() ) ) { IWsiExposeEnumAsString exposeEnumAsStringAnnotation = (IWsiExposeEnumAsString) CommonServices.getGosuIndustrialPark().evaluateAnnotation( wsiExposeEnumAsStringAnnotationInfo ); exposeEnumAsStringTypes.add( exposeEnumAsStringAnnotation.getType() ); } IAnnotationInfo wsiWebServiceAnnotationInfo = type.getTypeInfo().getAnnotationsOfType( WSI_WEB_SERVICE_ANNOTATION_TYPE.get() ).get( 0 ); IWsiWebService clsAnnot = (IWsiWebService) CommonServices.getGosuIndustrialPark().evaluateAnnotation( wsiWebServiceAnnotationInfo ); wsdl.declareNamespace( gw.internal.schema.gw.xsd.gw.gw_pl_wsdl_additions.Address.$QNAME ); String namespace = XmlServices.createTargetNamespace( type ); QName serviceName = new QName(namespace, clsAnnot.getServiceNameLocalPart() == null ? type.getRelativeName() : clsAnnot.getServiceNameLocalPart()); XmlNamespace tns = new XmlNamespace( serviceName.getNamespaceURI(), "tns" ); wsdl.setTargetNamespace$( new URI(serviceName.getNamespaceURI() ) ); wsdl.declareNamespace( wsdl.TargetNamespace(), "tns" ); wsdl.declareNamespace( new URI( gw.internal.schema.gw.xsd.w3c.soap11.Binding.$QNAME.getNamespaceURI() ), "soap11" ); wsdl.declareNamespace( new URI( gw.internal.schema.gw.xsd.w3c.soap12.Binding.$QNAME.getNamespaceURI() ), "soap12" ); wsdl.setName$( serviceName.getLocalPart() ); Schema schema = new Schema(); schema.setTargetNamespace$(wsdl.TargetNamespace()); schema.setElementFormDefault$(FormChoice.Qualified); schema.declareNamespace( wsdl.TargetNamespace(), "tns" ); WsiServiceInfo serviceInfo = new WsiServiceInfo( wsdl, schema, xsdRootURL, type, exposeEnumAsStringTypes ); List<IAnnotationInfo> parseOptionsAnnotations = type.getTypeInfo().getAnnotationsOfType( WSI_ADDITIONAL_SCHEMAS_ANNOTATION_TYPE.get() ); if ( ! parseOptionsAnnotations.isEmpty() ) { IAnnotationInfo parseOptionsAnnotationInfo = parseOptionsAnnotations.get( 0 ); IWsiAdditionalSchemas additionalSchemasAnnotation = (IWsiAdditionalSchemas) CommonServices.getGosuIndustrialPark().evaluateAnnotation( parseOptionsAnnotationInfo ); for ( XmlSchemaAccess additionalSchema : additionalSchemasAnnotation.getAdditionalSchemas() ) { XmlSchemaAccessImpl impl = (XmlSchemaAccessImpl) additionalSchema; XmlMarshaller.findOrImportSchema( impl.getSchemaIndex(), serviceInfo, null ); } } wsdl.Types().add( new TDefinitions_Types() ); wsdl.Types().get( 0 ).addChild( schema ); TDefinitions_PortType portType = new TDefinitions_PortType(); portType.setName$( serviceName.getLocalPart() + "PortType" ); wsdl.PortType().add( portType ); TDefinitions_Binding soap12WsdlBinding = new TDefinitions_Binding(); soap12WsdlBinding.setName$( serviceName.getLocalPart() + "Soap12Binding" ); soap12WsdlBinding.setType$( tns.qualify( serviceName.getLocalPart() + "PortType" ) ); wsdl.Binding().add( soap12WsdlBinding ); gw.internal.schema.gw.xsd.w3c.soap12.Binding soap12Binding = new gw.internal.schema.gw.xsd.w3c.soap12.Binding(); soap12Binding.setStyle$( gw.internal.schema.gw.xsd.w3c.soap12.enums.TStyleChoice.Document ); soap12Binding.setTransport$( new URI( "http://schemas.xmlsoap.org/soap/http" ) ); soap12WsdlBinding.addChild( soap12Binding ); TDefinitions_Binding soap11WsdlBinding = new TDefinitions_Binding(); soap11WsdlBinding.setName$( serviceName.getLocalPart() + "Soap11Binding" ); soap11WsdlBinding.setType$( tns.qualify( serviceName.getLocalPart() + "PortType" ) ); wsdl.Binding().add( soap11WsdlBinding ); gw.internal.schema.gw.xsd.w3c.soap11.Binding soap11Binding = new gw.internal.schema.gw.xsd.w3c.soap11.Binding(); soap11Binding.setStyle$( gw.internal.schema.gw.xsd.w3c.soap11.enums.TStyleChoice.Document ); soap11Binding.setTransport$( new URI( "http://schemas.xmlsoap.org/soap/http" ) ); soap11WsdlBinding.addChild( soap11Binding ); TDefinitions_Service service = new TDefinitions_Service(); service.setName$( serviceName.getLocalPart() ); TService_Port soap12Port = new TService_Port(); soap12Port.setName$( serviceName.getLocalPart() + "Soap12Port" ); soap12Port.setBinding$( tns.qualify( serviceName.getLocalPart() + "Soap12Binding" ) ); service.Port().add( soap12Port ); gw.internal.schema.gw.xsd.w3c.soap12.Address soap12Address = new gw.internal.schema.gw.xsd.w3c.soap12.Address(); soap12Address.setLocation$( new URI( requestURL ) ); soap12Port.addChild( soap12Address ); TService_Port soap11Port = new TService_Port(); soap11Port.setName$( serviceName.getLocalPart() + "Soap11Port" ); soap11Port.setBinding$( tns.qualify( serviceName.getLocalPart() + "Soap11Binding" ) ); service.Port().add( soap11Port ); gw.internal.schema.gw.xsd.w3c.soap11.Address soap11Address = new gw.internal.schema.gw.xsd.w3c.soap11.Address(); soap11Address.setLocation$( new URI( requestURL + "/soap11" ) ); soap11Port.addChild( soap11Address ); wsdl.Service().add( service ); Set<String> seenElements = new HashSet<String>(); // Iterate each method and check the args+return type for ( IMethodInfo m : ( (IGosuClassTypeInfo) type.getTypeInfo() ).getDeclaredMethods() ) { List<IAnnotationInfo> annotations = m.getAnnotationsOfType( WEB_METHOD_ANNOTATION_TYPE.get() ); if ( annotations.size() > 1 ) { throw new RuntimeException( "Multiple @WsiWebMethod annotations found on method " + m.getName() + " on class " + type.getName() ); } IWsiWebMethod annotation = annotations.size() == 1 ? (IWsiWebMethod) annotations.get( 0 ).getInstance() : null; if ( isOperation( m, annotation ) ) { createWsdlForOperation( m, annotation, tns, serviceInfo, soap12WsdlBinding, soap11WsdlBinding, seenElements, wsiInvocationContextType ); } } servlet.postConfigureWebservice( type, serviceInfo ); // Processing this annotation needs to be the last thing that occurs before the WSDL is returned for ( IAnnotationInfo wsiSchemaTransformAnnotationInfo : type.getTypeInfo().getAnnotationsOfType( WSI_SCHEMA_TRANSFORM_ANNOTATION_TYPE.get() ) ) { Object schemaTransformAnnotation = CommonServices.getGosuIndustrialPark().evaluateAnnotation( wsiSchemaTransformAnnotationInfo ); Function3 transform3 = (Function3) WSI_SCHEMA_TRANSFORM_ANNOTATION_TYPE.get().getTypeInfo().getProperty( "GWTransform" ).getAccessor().getValue( schemaTransformAnnotation ); if (transform3 != null ) { transform3.invoke( wsdl, schema, servlet.postConfigureWebservicePath(type, xsdRootURL) ); } else { Function2 transform2 = (Function2) WSI_SCHEMA_TRANSFORM_ANNOTATION_TYPE.get().getTypeInfo().getProperty( "Transform" ).getAccessor().getValue( schemaTransformAnnotation ); transform2.invoke( wsdl, schema ); } } return serviceInfo; } catch ( Exception ex ) { XmlServices.getLogger( IXmlLoggerFactory.Category.Runtime ) .debug("On " + type + " " + wsdl.asUTFString( XmlSerializationOptions.debug() ) + " caught " + ex); throw GosuExceptionUtil.forceThrow( ex ); } } public static boolean isOperation( IMethodInfo method, IWsiWebMethod annotation ) { return method.isPublic() && !method.isHidden() && !method.getName().startsWith("@") && !method.isStatic() && ( annotation == null || !annotation.isExclude() ); } private static void createWsdlForOperation( IMethodInfo m, IWsiWebMethod webmethodAnnotation, XmlNamespace tns, WsiServiceInfo serviceInfo, TDefinitions_Binding soap12WsdlBinding, TDefinitions_Binding soap11WsdlBinding, Set<String> seenElements, IType wsiInvocationContextType ) throws Exception { String name = makeUniqueName( m.getDisplayName(), seenElements ); if ( webmethodAnnotation != null && webmethodAnnotation.getOperationName() != null ) { name = webmethodAnnotation.getOperationName(); } QName operationQName = tns.qualify( name ); IMethodInfo oldMethod = serviceInfo.getOriginalMethods().put( operationQName, m ); if ( oldMethod != null ) { throw new WebServiceException( "Multiple methods found with the name " + name ); } Map<QName,MarshalInfo> paramMarshalInfoMap = serviceInfo.getMarshalInfoMap().get( operationQName ); if ( paramMarshalInfoMap == null ) { paramMarshalInfoMap = new HashMap<QName, MarshalInfo>(); serviceInfo.getMarshalInfoMap().put( operationQName, paramMarshalInfoMap ); } // create port operation TPortType_Operation portTypeOperation = new TPortType_Operation(); if (m.isDeprecated()) { TDocumented_Documentation documentation = new TDocumented_Documentation(); documentation.setText("@deprecated: " + m.getDeprecatedReason()); portTypeOperation.setDocumentation$(documentation); } portTypeOperation.setName$( name ); portTypeOperation.setInput$( new TOperation_Input() ); portTypeOperation.Input().setName$( name ); portTypeOperation.Input().setMessage$( tns.qualify( name ) ); serviceInfo.getWsdl().PortType().get( 0 ).Operation().add( portTypeOperation ); // create the binding to operation TBinding_Operation soap12BindingOp = new TBinding_Operation(); soap12BindingOp.setName$( name ); gw.internal.schema.gw.xsd.w3c.soap12.Operation soap12Operation = new gw.internal.schema.gw.xsd.w3c.soap12.Operation(); soap12Operation.setStyle$( gw.internal.schema.gw.xsd.w3c.soap12.enums.TStyleChoice.Document ); soap12Operation.setSoapActionRequired$(Boolean.FALSE); soap12BindingOp.addChild( soap12Operation ); soap12BindingOp.setInput$( new TBindingOperation_Input() ); soap12BindingOp.Input().setName$( name ); gw.internal.schema.gw.xsd.w3c.soap12.Body soap12Body = new gw.internal.schema.gw.xsd.w3c.soap12.Body(); soap12Body.setUse$( gw.internal.schema.gw.xsd.w3c.soap12.enums.UseChoice.Literal ); soap12BindingOp.Input().addChild( soap12Body ); soap12WsdlBinding.Operation().add( soap12BindingOp ); // create the binding to operation TBinding_Operation soap11BindingOp = new TBinding_Operation(); soap11BindingOp.setName$( name ); gw.internal.schema.gw.xsd.w3c.soap11.Operation soap11Operation = new gw.internal.schema.gw.xsd.w3c.soap11.Operation(); soap11Operation.setStyle$( gw.internal.schema.gw.xsd.w3c.soap11.enums.TStyleChoice.Document ); soap11BindingOp.addChild( soap11Operation ); soap11BindingOp.setInput$( new TBindingOperation_Input() ); soap11BindingOp.Input().setName$( name ); gw.internal.schema.gw.xsd.w3c.soap11.Body soap11Body = new gw.internal.schema.gw.xsd.w3c.soap11.Body(); soap11Body.setUse$( gw.internal.schema.gw.xsd.w3c.soap11.enums.UseChoice.Literal ); soap11BindingOp.Input().addChild( soap11Body ); soap11WsdlBinding.Operation().add( soap11BindingOp ); // Input TDefinitions_Message reqMsg = new TDefinitions_Message(); reqMsg.setName$( name ); serviceInfo.getWsdl().Message().add( reqMsg ); reqMsg.Part().add( new TMessage_Part() ); reqMsg.Part().get( 0 ).setElement$( tns.qualify( name ) ); reqMsg.Part().get( 0 ).setName$( "parameters" ); Element element = new Element(); element.setName$( name ); element.setComment( makeMethodSignatureForXmlComment( m ) ); boolean addedGWXsd = false; element.setComplexType$( new TopLevelElement_ComplexType() ); if ( m.getParameters().length > 0 ) { for ( IParameterInfo param : m.getParameters() ) { if ( param.getFeatureType().equals( wsiInvocationContextType ) ) { continue; // doesn't appear in WSDL } if ( element.ComplexType().Sequence() == null ) { element.ComplexType().setSequence$( new Sequence() ); } ExplicitGroup_Element typeEl = new ExplicitGroup_Element(); String paramName = param.getName(); typeEl.setName$( paramName ); if (!addedGWXsd && JavaTypes.DATE().isAssignableFrom(param.getFeatureType())) { ClassBasedMarshalInfo.addGWNamespaceIfNotAlreadyPresent(serviceInfo.getSchema()); addedGWXsd = true; } MarshalInfo marshalInfo = XmlMarshaller.addType( param.getFeatureType(), typeEl.getTypeInstance(), serviceInfo ); element.ComplexType().Sequence().Element().add( typeEl ); paramMarshalInfoMap.put( tns.qualify( paramName ), marshalInfo ); } } serviceInfo.getSchema().Element().add( element ); // Output String responseName = name + "Response"; soap12BindingOp.setOutput$( new TBindingOperation_Output() ); soap12BindingOp.Output().setName$( responseName ); gw.internal.schema.gw.xsd.w3c.soap12.Body soap12ResponseBody = new gw.internal.schema.gw.xsd.w3c.soap12.Body(); soap12ResponseBody.setUse$( gw.internal.schema.gw.xsd.w3c.soap12.enums.UseChoice.Literal ); soap12BindingOp.Output().addChild( soap12ResponseBody ); soap11BindingOp.setOutput$( new TBindingOperation_Output() ); soap11BindingOp.Output().setName$( responseName ); gw.internal.schema.gw.xsd.w3c.soap11.Body soap11ResponseBody = new gw.internal.schema.gw.xsd.w3c.soap11.Body(); soap11ResponseBody.setUse$( gw.internal.schema.gw.xsd.w3c.soap11.enums.UseChoice.Literal ); soap11BindingOp.Output().addChild( soap11ResponseBody ); portTypeOperation.setOutput$( new TOperation_Output() ); portTypeOperation.Output().setName$( responseName ); portTypeOperation.Output().setMessage$( tns.qualify( responseName ) ); TDefinitions_Message respMsg = new TDefinitions_Message(); respMsg.setName$( responseName ); serviceInfo.getWsdl().Message().add( respMsg ); respMsg.Part().add( new TMessage_Part() ); respMsg.Part().get( 0 ).setElement$( tns.qualify( responseName ) ); respMsg.Part().get( 0 ).setName$( "parameters" ); element = new Element(); element.setName$( responseName ); element.setComplexType$( new TopLevelElement_ComplexType() ); if ( !JavaTypes.pVOID().equals( m.getReturnType() ) ) { element.ComplexType().setSequence$( new Sequence() ); ExplicitGroup_Element typeEl = new ExplicitGroup_Element(); if (!addedGWXsd && JavaTypes.DATE().isAssignableFrom(m.getReturnType())) { ClassBasedMarshalInfo.addGWNamespaceIfNotAlreadyPresent(serviceInfo.getSchema()); } typeEl.setName$( "return" ); XmlMarshaller.addType( m.getReturnType(), typeEl.getTypeInstance(), serviceInfo ); element.ComplexType().Sequence().Element().add( typeEl ); } serviceInfo.getSchema().Element().add( element ); TreeSet<IType> expected = new TreeSet<IType>(COMPARATOR); expected.addAll( EXCEPTIONS_THROWN_BY_INFRASTRUCTURE.get()); for ( IExceptionInfo exceptionInfo : m.getExceptions() ) { IType exceptionType = exceptionInfo.getExceptionType(); expected.remove(exceptionType); addAFault(exceptionType, exceptionInfo.getDescription(), tns, serviceInfo, seenElements, portTypeOperation, soap12BindingOp, soap11BindingOp); } for (IType missing : expected) { addAFault(missing, null, tns, serviceInfo, seenElements, portTypeOperation, soap12BindingOp, soap11BindingOp); } } private static void addAFault(IType exceptionType, String description, XmlNamespace tns, WsiServiceInfo serviceInfo, Set<String> seenElements, TPortType_Operation portTypeOperation, TBinding_Operation soap12BindingOp, TBinding_Operation soap11BindingOp) { String faultName = exceptionType.getRelativeName(); TOperation_Fault fault = new TOperation_Fault(); fault.setName$( faultName ); fault.setComment(description); fault.setMessage$( tns.qualify( faultName ) ); TBindingOperation_Fault soap11BindingFault = new TBindingOperation_Fault(); soap11BindingOp.Fault().add( soap11BindingFault ); soap11BindingFault.setName$( faultName ); gw.internal.schema.gw.xsd.w3c.soap11.Fault soap11Fault = new gw.internal.schema.gw.xsd.w3c.soap11.Fault(); soap11Fault.setName$( faultName ); soap11Fault.setUse$( gw.internal.schema.gw.xsd.w3c.soap11.enums.UseChoice.Literal ); soap11BindingFault.addChild( soap11Fault ); TBindingOperation_Fault soap12BindingFault = new TBindingOperation_Fault(); soap12BindingOp.Fault().add( soap12BindingFault ); soap12BindingFault.setName$( faultName ); gw.internal.schema.gw.xsd.w3c.soap12.Fault soap12Fault = new gw.internal.schema.gw.xsd.w3c.soap12.Fault(); soap12Fault.setName$( faultName ); soap12Fault.setUse$( gw.internal.schema.gw.xsd.w3c.soap12.enums.UseChoice.Literal ); soap12BindingFault.addChild( soap12Fault ); if ( seenElements.add( faultName ) ) { TDefinitions_Message faultMessage = new TDefinitions_Message(); faultMessage.setName$( faultName ); serviceInfo.getWsdl().Message().add( faultMessage ); TMessage_Part part = new TMessage_Part(); faultMessage.Part().add( part ); part.setElement$( tns.qualify( faultName ) ); part.setName$( faultName ); Element faultElement = new Element(); faultElement.setName$( faultName ); faultElement.setComplexType$( new TopLevelElement_ComplexType() ); // TODO - should we include any properties in the exception element? Some thought needs to go into how this would work // We don't want to unnecessarily include random things, such as Message, because the customer might not // wish to include it. Perhaps an annotation where they explicitly add properties to be included? // faultElement.ComplexType().setSequence$( new Sequence() ); // for ( IPropertyInfo prop : exceptionType.getTypeInfo().getProperties() ) { // if ( ! prop.getOwnersType().equals( prop.getFeatureType() ) ) { // continue; // } // ExplicitGroup_Element propElement = new ExplicitGroup_Element(); // propElement.setName$( prop.getName() ); // MarshalInfo marshalInfo = XmlMarshaller.addType( prop.getFeatureType(), propElement.getTypeInstance(), createInfo ); // if ( marshalInfo != null ) { // faultElement.ComplexType().Sequence().Element().add( propElement ); // } // } serviceInfo.getSchema().Element().add( faultElement ); } portTypeOperation.Fault().add( fault ); } private static String makeMethodSignatureForXmlComment( IMethodInfo m ) { StringBuilder signature = new StringBuilder( m.getDisplayName() ); signature.append( '(' ); boolean first = true; for ( IParameterInfo param : m.getParameters() ) { IType paramFeatureType = param.getFeatureType(); if ( WSI_INVOCATION_CONTEXT_TYPE.get().equals( paramFeatureType ) ) { continue; } if ( ! first ) { signature.append( ", " ); } signature.append( paramFeatureType.getRelativeName() ); first = false; } signature.append( ')' ); IType returnType = m.getReturnType(); if ( ! returnType.equals( JavaTypes.pVOID() ) ) { signature.append( " : " ); signature.append( returnType.getRelativeName() ); } return signature.toString(); } private static String makeUniqueName( String name, Set<String> seenElements ) { if ( ! seenElements.add( name ) ) { int suffix = 2; while ( true ) { String newName = name + suffix++; if ( seenElements.add( newName ) ) { name = newName; break; } } } return name; } }