/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.internal.xml.ws.typeprovider;
/**
* This class represents a port definition within a wsdl, there is a corresponding info
* that contains the properties and methods information that is lazy loaded.
*/
import gw.config.CommonServices;
import gw.fs.IFile;
import gw.internal.xml.ws.IWsdlConfig;
import gw.internal.xml.ws.WsdlSoapHeaders;
import gw.internal.xml.ws.WsiAdditions;
import gw.internal.xml.xsd.typeprovider.XmlSchemaIndex;
import gw.internal.xml.xsd.typeprovider.XmlTypeData;
import gw.internal.xml.xsd.typeprovider.schema.*;
import gw.internal.xml.xsd.typeprovider.schemaparser.SoapVersion;
import gw.internal.xml.ws.rt.WsdlOperationInfo;
import gw.internal.xml.ws.rt.WsdlPortImpl;
import gw.internal.xml.ws.typeprovider.paraminfo.AnonymousElementException;
import gw.internal.xml.ws.typeprovider.paraminfo.ArrayWsdlOperationParameterInfo;
import gw.internal.xml.ws.typeprovider.paraminfo.WsdlOperationParameterInfo;
import gw.internal.xml.xsd.typeprovider.IWsdlPortTypeData;
import gw.internal.xml.xsd.typeprovider.IXmlSchemaElementTypeData;
import gw.internal.xml.xsd.typeprovider.IXmlType;
import gw.internal.xml.xsd.typeprovider.XmlSchemaPropertySpec;
import gw.internal.xml.xsd.typeprovider.XmlSchemaTypeSchemaInfo;
import gw.lang.reflect.ConstructorInfoBuilder;
import gw.lang.reflect.IConstructorHandler;
import gw.lang.reflect.IConstructorInfo;
import gw.lang.reflect.IFeatureInfo;
import gw.lang.reflect.IFileBasedFeature;
import gw.lang.reflect.ILocationAwareFeature;
import gw.lang.reflect.IMethodCallHandler;
import gw.lang.reflect.IMethodInfo;
import gw.lang.reflect.IPropertyAccessor;
import gw.lang.reflect.IPropertyInfo;
import gw.lang.reflect.IType;
import gw.lang.reflect.LocationInfo;
import gw.lang.reflect.MethodInfoBuilder;
import gw.lang.reflect.ParameterInfoBuilder;
import gw.lang.reflect.PropertyInfoBuilder;
import gw.lang.reflect.TypeSystem;
import gw.lang.reflect.java.IJavaClassInfo;
import gw.lang.reflect.java.IJavaType;
import gw.lang.reflect.java.JavaTypes;
import gw.util.GosuExceptionUtil;
import gw.util.ILogger;
import gw.util.Pair;
import gw.internal.schema.gw.xsd.w3c.xmlschema.types.complex.AnyType;
import gw.util.concurrent.LockingLazyVar;
import gw.xml.XmlElement;
import gw.xml.XmlException;
import java.util.*;
import java.net.URI;
import java.net.URISyntaxException;
import javax.xml.namespace.QName;
public class WsdlPortTypeData extends XmlTypeData implements IWsdlPortTypeData, ILocationAwareFeature {
private final Wsdl _wsdl;
protected final WsdlPort _wsdlDefPort;
private final String _name;
private boolean _initialized;
private List<IPropertyInfo> _props;
private List<IMethodInfo> _methods;
private WsdlService _service;
private List<IConstructorInfo> _ctors;
private final IFile _resourceFile;
private final boolean _isService;
private LockingLazyVar<URI> _address = new LockingLazyVar<URI>() {
@Override
protected URI init() {
try {
return extractAddress( _wsdlDefPort );
}
catch ( URISyntaxException e ) {
throw GosuExceptionUtil.forceThrow( e );
}
}
};
protected static LockingLazyVar<IType> _wsdlConfigType = new LockingLazyVar<IType>() {
@Override
protected IType init() {
return TypeSystem.getByFullName( "gw.xml.ws.WsdlConfig" );
}
};
protected static LockingLazyVar<IType> _wsdlPortType = new LockingLazyVar<IType>() {
@Override
protected IType init() {
return TypeSystem.getByFullName( "gw.xml.ws.IWsdlPort" );
}
};
protected static LockingLazyVar<IType> _anyType = new LockingLazyVar<IType>() {
@Override
protected IType init() {
return TypeSystem.getByFullName( "gw.xsd.w3c.xmlschema.types.complex.AnyType" );
}
};
private final Map<WsdlBindingOperation, WsdlSoapHeadersTypeDataClass> _soapHeadersTypeDataByBindingOperation;
/**
* Create a new port definition
*
* @param name the name of this port
* @param wsdlDefPort the Port element from the wsdl
* @param wsdl the wsdl that this port is defined in
* @param service the service this port is on
* @param resourceFile the resource file that contains this port
* @param isService is service
* @param soapHeadersTypeDataByBindingOperation
*/
public WsdlPortTypeData( String name, WsdlPort wsdlDefPort, final Wsdl wsdl, WsdlService service, IFile resourceFile, boolean isService, Map<WsdlBindingOperation, WsdlSoapHeadersTypeDataClass> soapHeadersTypeDataByBindingOperation ) {
_name = name;
_wsdlDefPort = wsdlDefPort;
_wsdl = wsdl;
_service = service;
_resourceFile = resourceFile;
_isService = isService;
_soapHeadersTypeDataByBindingOperation = soapHeadersTypeDataByBindingOperation;
if ( getLogger().isDebugEnabled()) {
getLogger().debug("WsdlPortTypeInfo created for " + name);
}
}
public Wsdl getWsdl() {
return _wsdl;
}
public ILogger getLogger() {
return _wsdl.getLogger();
}
public void maybeInit() {
if ( ! _initialized ) {
_methods = new ArrayList<IMethodInfo>();
_props = new ArrayList<IPropertyInfo>();
addPortPropertiesAndMethods( this, _wsdl, _props, _methods, _wsdlDefPort );
_ctors = makeConstructors();
getLogger().debug("WsdlPortTypeInfo for " + _name + " properties=" + _props);
getLogger().debug("WsdlPortTypeInfo for " + _name + " methods=" + _methods);
_initialized = true;
}
}
@Override
public String getName() {
return _name;
}
@Override
public List<IPropertyInfo> getDeclaredProperties() {
maybeInit();
return _props;
}
@Override
public List<IMethodInfo> getDeclaredMethods() {
maybeInit();
return _methods;
}
@Override
public List<? extends IConstructorInfo> getDeclaredConstructors() {
maybeInit();
return _ctors;
}
private List<IConstructorInfo> makeConstructors() {
List<IConstructorInfo> list = new ArrayList<IConstructorInfo>();
if ( getLogger().isDebugEnabled()) {
getLogger().debug("WsdlServiceTypeInfo.getDeclaredConstructors for " + _wsdlDefPort.getQName());
}
final IType configIType = TypeSystem.getByFullName( "gw.xml.ws.WsdlConfig" );
list.add(new ConstructorInfoBuilder()
.withParameters(new ParameterInfoBuilder().withName("config").withDescription("This is the xml representing the configuration of this client").withType(configIType))
.withConstructorHandler(new IConstructorHandler() {
@Override
public Object newInstance(Object... args) {
return constructPort(args[0]);
}
}).build(this));
list.add(new ConstructorInfoBuilder()
.withConstructorHandler(new IConstructorHandler() {
@Override
public Object newInstance(Object... args) {
return constructPort( null );
}
}).build(this));
if ( getLogger().isDebugEnabled() ) {
getLogger().debug("WsdlServiceTypeInfo for " + _service.getQName() + " constructors=" + list);
}
return list;
}
private Object constructPort( Object arg ) {
QName serviceQName = _service.getQName();
QName portQName = _wsdlDefPort.getQName();
IWsdlConfig config = (IWsdlConfig) arg;
if ( config == null ) {
config = (IWsdlConfig) _wsdlConfigType.get().getTypeInfo().getConstructor().getConstructor().newInstance();
}
configure( serviceQName, portQName, config );
return new WsdlPortImpl( getType(), _resourceFile, serviceQName, getWsdl(), portQName, config, _wsdlDefPort );
}
public URI getAddress() {
return _address.get();
}
public QName getPortName() {
return _wsdlDefPort.getQName();
}
public QName getServiceName() {
return _service.getQName();
}
@Override
public boolean isFinal() {
return true;
}
@Override
public boolean isEnum() {
return false;
}
@Override
public IType getSuperType() {
return JavaTypes.OBJECT();
}
@Override
public boolean prefixSuperProperties() {
return false;
}
@Override
public long getFingerprint() {
return 0; // TODO
}
@Override
public Class getBackingClass() {
return WsdlPortImpl.class;
}
@Override
public IJavaClassInfo getBackingClassInfo() {
return JavaTypes.getSystemType(WsdlPortImpl.class).getBackingClassInfo();
}
@Override
public XmlSchemaIndex<?> getSchemaIndex() {
return _wsdlDefPort.getSchemaIndex();
}
/** This will add ehte port properties and methods to either the port class or
* the service class.
*
* @param container the class that will contain these methods and properties
* @param wsdl the wsdl in which the prot or service was defined
* @param props the properties array for the prot or service
* @param methods the methods array for the port or service
* @param port the port Wsdl definition @return the address for this port
*/
protected void addPortPropertiesAndMethods( IFeatureInfo container, final Wsdl wsdl, final List<IPropertyInfo> props, final List<IMethodInfo> methods, final WsdlPort port ) {
addMethodForOperations(container, methods, port, wsdl);
addProperties( container, props );
props.add( new PropertyInfoBuilder().withName( "ADDRESS" )
.withType( TypeSystem.get( URI.class ) )
.withWritable( false )
.withStatic()
.withAccessor( new IPropertyAccessor() {
@Override
public Object getValue( Object ctx ) {
return getAddress();
}
@Override
public void setValue( Object ctx, Object value ) {
throw new UnsupportedOperationException();
}
} ).build(container));
props.add( new PropertyInfoBuilder().withName( "PORT_QNAME" )
.withType( TypeSystem.get( QName.class ) )
.withWritable( false )
.withStatic()
.withAccessor( new IPropertyAccessor() {
@Override
public Object getValue( Object ctx ) {
return getPortName();
}
@Override
public void setValue( Object ctx, Object value ) {
throw new UnsupportedOperationException();
}
} ).build(container));
props.add( new PropertyInfoBuilder().withName( "SERVICE_QNAME" )
.withType( TypeSystem.get( QName.class ) )
.withWritable( false )
.withStatic()
.withAccessor( new IPropertyAccessor() {
@Override
public Object getValue( Object ctx ) {
return getServiceName();
}
@Override
public void setValue( Object ctx, Object value ) {
throw new UnsupportedOperationException();
}
} ).build(container));
}
private void addProperties( IFeatureInfo container, List<IPropertyInfo> props ) {
IType logType = TypeSystem.getJavaType( ILogger.class);
props.add(new PropertyInfoBuilder().withName("Logger")
.withLocation(getLocationInfo())
.withType(logType)
.withWritable(true)
.withAccessor(new IPropertyAccessor() {
@Override
public Object getValue(Object ctx) {
return ((WsdlPortImpl) ctx).getLogger();
}
@Override
public void setValue(Object ctx, Object value) {
((WsdlPortImpl) ctx).setLogger((ILogger) value);
}
}).build(container));
props.add(new PropertyInfoBuilder().withName("Config")
.withLocation(getLocationInfo())
.withType(TypeSystem.getByFullName("gw.xml.ws.WsdlConfig"))
.withWritable(false)
.withAccessor(new IPropertyAccessor() {
@Override
public Object getValue(Object ctx) {
return ((WsdlPortImpl) ctx).getConfig();
}
@Override
public void setValue(Object ctx, Object value) {
throw new UnsupportedOperationException();
}
}).build(container));
props.add( new PropertyInfoBuilder().withName( "PortQName" )
.withLocation(getLocationInfo())
.withType(TypeSystem.get(QName.class))
.withWritable( false )
.withAccessor( new IPropertyAccessor() {
@Override
public Object getValue( Object ctx ) {
return ((WsdlPortImpl)ctx).getPortQName();
}
@Override
public void setValue( Object ctx, Object value ) {
throw new UnsupportedOperationException();
}
} ).build(container));
props.add( new PropertyInfoBuilder().withName( "ServiceQName" )
.withLocation(getLocationInfo())
.withType(TypeSystem.get(QName.class))
.withWritable( false )
.withAccessor( new IPropertyAccessor() {
@Override
public Object getValue( Object ctx ) {
return ((WsdlPortImpl)ctx).getServiceQName();
}
@Override
public void setValue( Object ctx, Object value ) {
throw new UnsupportedOperationException();
}
} ).build(container));
}
private void addMethodForOperations( IFeatureInfo container, List<IMethodInfo> methods, final WsdlPort wsdlPort, final Wsdl wsdl ) {
WsdlBinding binding = wsdlPort.getBinding();
WsdlPortType portType = binding.getPortType();
final List<WsdlBindingOperation> list = binding.getBindingOperations();
int incomingSize = methods.size();
for (WsdlBindingOperation bindingOp : list) {
final WsdlPortTypeOperation op = portType.getOperationByName( bindingOp.getName() );
if (op == null) {
getLogger().warn("On " + _service.getQName() + " operation=" + bindingOp.getName() + ": no operation in port");
continue;
}
if (bindingOp.getBindingInput() != null) {
if (checkUseEncoded(bindingOp, bindingOp.getBindingInput().getSoapBody())) {
continue;
}
}
if (bindingOp.getBindingOutput() != null) {
if (checkUseEncoded(bindingOp, bindingOp.getBindingOutput().getSoapBody())) {
continue;
}
}
final String opName = op.getName();
final WsdlPortTypeInput inputWsdl = op.getInput();
final List<WsdlPart> inputParts = getIncludedParts( inputWsdl.getMessage().getParts(), bindingOp.getBindingInput().getSoapBody() );
final String soapAction = getSoapAction(bindingOp);
final WsdlOperationInputInfo input = convertInputParametersXMLType( op, inputParts, wsdl );
if ( input == null ) {
getLogger().warn("On " + _service.getQName() + " operation=" + bindingOp.getName() + ": cannot convert request parameters");
continue; // skip this operation
}
WsdlOperationOutputInfo outputInfo = null;
if ( op.getOutput() != null ) {
final WsdlPortTypeOutput outputWsdl = op.getOutput();
final List<WsdlSoapHeader> outExtList = bindingOp.getBindingOutput().getSoapHeaders();
@SuppressWarnings({"unchecked"})
final List<WsdlPart> outputParts = outputWsdl.getMessage().getParts();
//noinspection LoopStatementThatDoesntLoop
for ( WsdlSoapHeader el : outExtList ) {
for (Iterator<WsdlPart> itr = outputParts.iterator(); itr.hasNext(); ) {
WsdlPart part = itr.next();
if (part.getName().equals(el.getPartName())) {
itr.remove();
break;
}
}
}
outputInfo = convertOutputToReturnType( op, outputParts, wsdl );
if ( outputInfo == null ) {
getLogger().warn("On " + _service.getQName() + " operation=" + bindingOp.getName() + ": cannot convert response");
continue; // skip this operation
}
}
final WsdlOperationInfo opTypeData = new WsdlOperationInfo( opName, soapAction, input, outputInfo, wsdlPort );
final MethodInfoBuilder opBldr = new MethodInfoBuilder()
.withLocation( getLocationInfo() )
.withName( XmlSchemaIndex.normalizeName( opName, XmlSchemaIndex.NormalizationMode.PRESERVECASE ) );
opBldr.withReturnType( outputInfo == null ? JavaTypes.pVOID() : outputInfo.getReturnType() );
List<ParameterInfoBuilder> params = addParameters( input );
// methodName( params... )
opBldr.withParameters( params.toArray( new ParameterInfoBuilder[ params.size() ] ) );
opBldr.withCallHandler(new IMethodCallHandler() {
@Override
public Object handleCall(Object ctx, Object... args) {
return handleOperationCall((WsdlPortImpl) ctx, opTypeData, args);
}
});
methods.add(opBldr.build(container));
// methodName( params..., soapheadersobject )
final WsdlSoapHeadersTypeDataClass wsdlSoapHeadersTypeData = _soapHeadersTypeDataByBindingOperation.get( bindingOp );
if ( wsdlSoapHeadersTypeData != null ) {
opBldr.withParameters( addHeadersToParams(wsdlSoapHeadersTypeData, params) );
opBldr.withCallHandler( new IMethodCallHandler() {
@Override
public Object handleCall( Object ctx, Object... args ) {
return handleOperationCall( (WsdlPortImpl)ctx, opTypeData, args );
}
} );
methods.add( opBldr.build( container ) );
}
addAsyncOperationToMethods(container, methods, opName, opTypeData, params, _wsdlDefPort.getBinding().getSoapBinding().getSoapVersion(), wsdlSoapHeadersTypeData);
}
if (incomingSize == methods.size()) {
getLogger().warn("On " + _service.getQName() + ": no supported operations");
}
final MethodInfoBuilder opBldr = new MethodInfoBuilder()
.withLocation( getLocationInfo() )
.withName("document_literal");
opBldr.withReturnType( TypeSystem.get( XmlElement.class ) );
opBldr.withParameters( new ParameterInfoBuilder().withName( "document" ).withType( XmlElement.class ) );
opBldr.withCallHandler(new IMethodCallHandler() {
@Override
public Object handleCall(Object ctx, Object... args) {
return handleOperationCall( (WsdlPortImpl)ctx, null, args );
}
});
methods.add(opBldr.build(container));
final MethodInfoBuilder opAsyncBldr = new MethodInfoBuilder()
.withLocation( getLocationInfo() )
.withName("async_document_literal");
opAsyncBldr.withReturnType( WsdlPortImpl.getParameterizedAsyncResponseType( null, _wsdlDefPort.getBinding().getSoapBinding().getSoapVersion(), false ) );
opAsyncBldr.withParameters( new ParameterInfoBuilder().withName( "document" ).withType( XmlElement.class ) );
opAsyncBldr.withCallHandler(new IMethodCallHandler() {
@Override
public Object handleCall(Object ctx, Object... args) {
return handleOperationAsyncCall((WsdlPortImpl)ctx, null, args );
}
});
methods.add(opAsyncBldr.build(container));
}
private List<WsdlPart> getIncludedParts( List<WsdlPart> parts, WsdlSoapBody soapBody ) {
if ( soapBody != null ) {
if ( soapBody.getParts() == null ) {
return parts;
}
else {
List<WsdlPart> includedParts = new ArrayList<WsdlPart>( parts.size() );
for ( WsdlPart part : parts ) {
if ( soapBody.getParts().contains( part.getName() ) ) {
includedParts.add( part );
}
}
return includedParts;
}
}
throw new XmlException( "No soap body found" );
}
private boolean checkUseEncoded(WsdlBindingOperation bindingOp, WsdlSoapBody body) {
if (body != null) {
if ("encoded".equals(body.getUse())) {
getLogger().warn("On " + _service.getQName() + " operation=" + bindingOp.getName() + ": use=\"encoded\" not supported");
return true;
}
}
return false;
}
// Add an async method to the methods list
private void addAsyncOperationToMethods( IFeatureInfo container,
List<IMethodInfo> methods,
final String opName,
final WsdlOperationInfo opTypeData,
List<ParameterInfoBuilder> params,
final SoapVersion soapVersion,
WsdlSoapHeadersTypeDataClass wsdlSoapHeadersTypeData) {
final MethodInfoBuilder opAsyncBldr = new MethodInfoBuilder()
.withLocation( getLocationInfo() )
.withName("async_" + XmlSchemaIndex.normalizeName(opName, XmlSchemaIndex.NormalizationMode.PRESERVECASE));
opAsyncBldr.withReturnType(WsdlPortImpl.getParameterizedAsyncResponseType(opTypeData, soapVersion, false));
// methodName( params... )
opAsyncBldr.withParameters(params.toArray(new ParameterInfoBuilder[params.size()]));
opAsyncBldr.withCallHandler(new IMethodCallHandler() {
@Override
public Object handleCall(Object ctx, Object... args) {
return handleOperationAsyncCall((WsdlPortImpl) ctx, opTypeData, args);
}
});
methods.add(opAsyncBldr.build(container));
// methodName( params..., soapheadersobject )
if ( wsdlSoapHeadersTypeData != null ) {
opAsyncBldr.withParameters(addHeadersToParams(wsdlSoapHeadersTypeData, params));
opAsyncBldr.withCallHandler( new IMethodCallHandler() {
@Override
public Object handleCall( Object ctx, Object... args ) {
return handleOperationAsyncCall((WsdlPortImpl) ctx, opTypeData, args );
}
} );
methods.add( opAsyncBldr.build( container ) );
}
}
private ParameterInfoBuilder[] addHeadersToParams(WsdlSoapHeadersTypeDataClass wsdlSoapHeadersTypeData, List<ParameterInfoBuilder> paramsSource) {
List<ParameterInfoBuilder> params = new ArrayList<ParameterInfoBuilder>(paramsSource);
params.add(new ParameterInfoBuilder()
.withName("soapheaders")
.withType(wsdlSoapHeadersTypeData.getType())
);
return params.toArray(new ParameterInfoBuilder[params.size()]);
}
protected Object handleOperationCall(WsdlPortImpl ctx, WsdlOperationInfo opTypeData, Object[] args) {
return ctx.invoke(opTypeData, args);
}
protected Object handleOperationAsyncCall(WsdlPortImpl ctx, WsdlOperationInfo opTypeData, Object[] args) {
return ctx.invokeAsync( opTypeData, args );
}
private static List<ParameterInfoBuilder> addParameters( WsdlOperationInputInfo input ) {
List<ParameterInfoBuilder> params = new ArrayList<ParameterInfoBuilder>();
for ( Pair<WsdlOperationParameterInfo,Boolean> param : input.getParameterInfos() ) {
IType type = param.getFirst().getType();
if ( param.getSecond() ) {
type = JavaTypes.LIST().getGenericType().getParameterizedType( type );
}
params.add( new ParameterInfoBuilder().withName( param.getFirst().getName() ).withType( type ) );
}
return params;
}
private static String getSoapAction( WsdlBindingOperation bindingOp ) {
WsdlSoapOperation wsdlSoapOperation = bindingOp.getSoapOperation();
return wsdlSoapOperation == null ? "" : wsdlSoapOperation.getSoapAction();
}
private static WsdlOperationOutputInfo convertOutputToReturnType( WsdlPortTypeOperation op, List<WsdlPart> parts, final Wsdl wsdl ) {
WsdlOperationOutputInfo outputInfo = null;
if ( parts.size() == 1 ) { // not a single part = not unwrapable
WsdlPart part = parts.get( 0 );
QName elementName = part.getElementName();
IXmlType type = (IXmlType) part.getSchemaIndex().getGosuTypeByXmlSchemaElementQName( elementName );
IXmlSchemaElementTypeData typeData = (IXmlSchemaElementTypeData) type.getTypeData();
if ( hasNoAnys( typeData ) ) {
outputInfo = getUnwrappedReturnTypeIfPossible(op, (Wsdl) part.getSchemaIndex(), outputInfo, elementName, type);
}
if ( outputInfo == null ) {
try {
outputInfo = new WsdlOperationOutputInfo( type, elementName ); // fall back to just returning the Response element
outputInfo.setUseParentElement( true );
}
catch ( AnonymousElementException ex ) {
throw new RuntimeException( "On '" + op.getName() + "'", ex ); // should never happen since this is a top-level element assigned to a part
}
}
return outputInfo;
}
else {
wsdl.getLogger().warn( "In WSDL " + wsdl.getPackageName() + ", operation " + op.getName() + " was ignored since multiple output parts are not supported" );
return null;
}
}
private static WsdlOperationOutputInfo getUnwrappedReturnTypeIfPossible(WsdlPortTypeOperation op, Wsdl wsdl, WsdlOperationOutputInfo outputInfo, QName elementName, IXmlType type) {
try {
WsdlOperationOutputInfo unwrappedOutputInfo = new WsdlOperationOutputInfo( type, elementName ); // in case we are able to unwrap request
String operationName = op.getName() + "Response";
if ( operationName.equals( elementName.getLocalPart() ) ) { // operation name + "Response" has to equal element name for unwrapable
XmlSchemaTypeSchemaInfo schemaInfo = wsdl.getElementInfoByXmlSchemaElementQName( elementName );
if (!isUnwrappable(schemaInfo)) {
return null;
}
if ( schemaInfo.getProperties().size() <= 1 ) {
unwrappedOutputInfo.addUnwrapLevel( type, elementName ); // unwrap the Response element
unwrappedOutputInfo.setSchemaInfo( schemaInfo );
outputInfo = unwrappedOutputInfo;
}
}
if ( outputInfo != null ) {
if ( outputInfo.getSchemaInfo().getProperties().size() > 0 ) {
// we're now totally unwrapped to the level where the parameters are (only 1 parameter in case of response)
XmlSchemaPropertySpec firstProperty = outputInfo.getSchemaInfo().getProperties().get( 0 );
WsdlOperationParameterInfo paramInfo = WsdlOperationParameterInfo.create( firstProperty );
if ( firstProperty.isPlural() ) {
outputInfo = new WsdlOperationOutputInfo( type, elementName );
outputInfo.setReturnParameterInfo( new ArrayWsdlOperationParameterInfo( type, elementName, paramInfo ) );
outputInfo.setUseParentElement( true );
}
else {
outputInfo.setReturnParameterInfo( paramInfo );
}
}
else {
outputInfo.setReturnParameterInfo( null );
}
}
}
catch ( AnonymousElementException ignored ) {
outputInfo = null;
}
return outputInfo;
}
private static boolean hasNoAnys( IXmlSchemaElementTypeData typeData ) {
XmlSchemaTypeSchemaInfo schemaInfo = typeData.getSchemaInfo();
XmlSchemaType xsdType = schemaInfo.getXsdType();
return schemaInfo.getAttributeNames().isEmpty() && xsdType.getAnyRecursiveIncludingSupertypes() == null && xsdType.getAnyAttributeRecursiveIncludingSupertypes() == null;
}
private static WsdlOperationInputInfo convertInputParametersXMLType( WsdlPortTypeOperation op, List<WsdlPart> parts, final Wsdl wsdl) {
WsdlOperationInputInfo inputInfo;
if ( parts.size() == 1 ) { // not a single part = not unwrapable
WsdlPart part = parts.get( 0 );
QName elementName = part.getElementName();
IXmlType type = (IXmlType) part.getSchemaIndex().getGosuTypeByXmlSchemaElementQName( elementName );
IXmlSchemaElementTypeData typeData = (IXmlSchemaElementTypeData) type.getTypeData();
inputInfo = getUnwrappedParametersIfPossible(op, (Wsdl) part.getSchemaIndex(), elementName, type, typeData);
if ( inputInfo == null ) {
try {
inputInfo = new WsdlOperationInputInfo( type, elementName ); // fall back to just returning the Response element
}
catch ( AnonymousElementException ex ) {
throw new RuntimeException( "On '" + op.getName() + "'", ex ); // should never happen since this is a top-level element assigned to a part
}
}
return inputInfo;
}
else {
wsdl.getLogger().warn( "In WSDL " + wsdl.getPackageName() + ", operation " + op.getName() + " was ignored since multiple input parts are not supported" );
return null;
}
}
private static WsdlOperationInputInfo getUnwrappedParametersIfPossible(WsdlPortTypeOperation op, Wsdl wsdl, QName elementName, IXmlType type, IXmlSchemaElementTypeData typeData) {
WsdlOperationInputInfo inputInfo = null;
if ( hasNoAnys( typeData ) ) {
try {
String operationName = op.getName();
if ( operationName.equals( elementName.getLocalPart() ) ) { // operation name has to equal element name for unwrapable
inputInfo = new WsdlOperationInputInfo( type, elementName ); // in case we are able to unwrap request
XmlSchemaTypeSchemaInfo schemaInfo = wsdl.getElementInfoByXmlSchemaElementQName( elementName );
inputInfo.setSchemaInfo( schemaInfo );
if (!isUnwrappable(schemaInfo)) {
return null;
}
// we're now totally unwrapped to the level where the parameters are
List<Pair<WsdlOperationParameterInfo,Boolean>> paramInfos = new ArrayList<Pair<WsdlOperationParameterInfo, Boolean>>( inputInfo.getSchemaInfo().getProperties().size() );
for ( XmlSchemaPropertySpec propertySpec : inputInfo.getSchemaInfo().getProperties() ) {
paramInfos.add( new Pair<WsdlOperationParameterInfo, Boolean>( WsdlOperationParameterInfo.create( propertySpec ), propertySpec.isPlural() ) );
}
inputInfo.setParameterInfos( paramInfos );
}
}
catch ( AnonymousElementException ignored ) {
return null;
}
}
return inputInfo;
}
private static boolean isUnwrappable(XmlSchemaTypeSchemaInfo schemaInfo) {
if (!(schemaInfo.getXsdType() instanceof XmlSchemaComplexType)) {
return false;
}
if (schemaInfo.isMixed()) {
return false;
}
XmlSchemaComplexType complexSchemaInfo = (XmlSchemaComplexType) schemaInfo.getXsdType();
XmlSchemaContentModel model = complexSchemaInfo.getContentModel();
if (!(model instanceof XmlSchemaComplexContent)) {
return false;
}
XmlSchemaComplexContent complexContent = (XmlSchemaComplexContent) model;
if (!(complexContent.getContent() instanceof XmlSchemaComplexContentRestriction)) {
return false;
}
XmlSchemaComplexContentRestriction contentRestriction = (XmlSchemaComplexContentRestriction) complexContent.getContent();
return contentRestriction.getBaseTypeName().equals(AnyType.$QNAME);
}
protected URI extractAddress( WsdlPort port ) throws URISyntaxException {
URI uri = null;
if (port != null) {
String locationString = port.getLocation();
if ( locationString != null ) {
uri = new URI( locationString );
}
locationString = getOverrideAddress();
WsdlGwAddress gwAddress = port.getGwAddress();
if ( locationString == null && gwAddress != null ) {
locationString = gwAddress.getLocation();
}
if ( locationString != null ) {
URI gwUri = WsiAdditions.getInstance().substituteProductCode( locationString );
if ( gwUri != null ) {
uri = gwUri;
}
}
}
return uri;
}
protected String getOverrideAddress() {
return null;
}
protected void configure( QName serviceName, QName portName, IWsdlConfig config ) {
}
@Override
public List<Class<?>> getAdditionalInterfaces() {
return Arrays.asList(IWsdlPortTypeData.class, ILocationAwareFeature.class);
}
@Override
public boolean isService() {
return _isService;
}
public WsdlPort getWsdlDefPort() {
return _wsdlDefPort;
}
@Override
public List<? extends IType> getInterfaces() {
List<IType> list = new ArrayList<IType>(super.getInterfaces());
list.add(_wsdlPortType.get());
return list;
}
@Override
public LocationInfo getLocationInfo() {
return _wsdlDefPort.getLocationInfo();
}
}