How can I have two separate web services with the same namespace and local name queries at different endpoints?

I am trying to create 2 separate web services, both within the same spring deployment, and with wsdl generated from the same xsd schemes, but they need to be redirected to two separate endpoints so that I can handle requests differently in separate contexts.

Example:

Webservice 1: subset of access, lower privileges and security restrictions

Webservice 2: higher privileges

<sws:dynamic-wsdl id="spml-readonly" portTypeName="SpmlReadOnlyService" locationUri="SpmlReadOnly"> <sws:xsd location="/WEB-INF/xsd/spml/pstc_spmlv2_core.xsd"/> </sws:dynamic-wsdl> <sws:dynamic-wsdl id="spml-crud" portTypeName="SpmlCrudService" locationUri="SpmlCrud"> <sws:xsd location="/WEB-INF/xsd/spml/pstc_spmlv2_core.xsd"/> <sws:xsd location="/WEB-INF/xsd/spml/pstc_spmlv2_search.xsd"/> <sws:xsd location="/WEB-INF/xsd/spml/pstc_spmlv2_batch.xsd"/> </sws:dynamic-wsdl> 

Now that both wsdls are based on the same xsds, the "namespace" and "localPart" requests hit the wire the same way, regardless of which web service I click (/ SpmlReadOnly or / SpmlCrud).

Therefore, this eliminates the obsolete value of PayloadRootQNameEndpointMapping, since localPart and the namespace are still identical, etc., and my current configuration simply redirects requests to one endpoint method handler, and I cannot distinguish which web service was called:

  @PayloadRoot(namespace = NAMESPACE_URI, localPart = "lookupRequest") @ResponsePayload public Source handleLookupRequest(SoapMessage message) throws Exception { ... } 

Can I do what can I do? If xsd are shared and have the same namespaces in the root schema of the schema and the same localPart method requests, will there ever be an opportunity to distinguish them and map them to two different endpoints? Any information on this would be helpful! I hope that I do not need to configure two separate Wwws and deploy them separately with my own code bases on the server!

Thanks Damian

+7
source share
1 answer

You need something that combines a URI and PayloadRoot . Unfortunately, Spring-Ws has nothing of the kind. But since it is very extensible, it is really easy to achieve.

TL DR

See This thread on GitHub for a working example.

More details

You need to create a combined URI + QName mapping to instances of org.springframework.ws.server.endpoint.MethodEndpoint . You should also minimize code that duplicates existing Spring -Ws functions.

So 1) You need to explicitly configure Spring -Ws annotations without using <sws:annotation-driven /> :

This is your requirement (with my schemes):

 <ws:dynamic-wsdl id="spml-readonly" portTypeName="SpmlReadOnlyService" locationUri="SpmlReadOnly"> <ws:xsd location="classpath:springws/model/schema.xsd" /> </ws:dynamic-wsdl> <ws:dynamic-wsdl id="spml-crud" portTypeName="SpmlCrudService" locationUri="SpmlCrud"> <ws:xsd location="classpath:springws/model/schema.xsd" /> <ws:xsd location="classpath:springws/model/schema2.xsd" /> </ws:dynamic-wsdl> 

This is all you need to do manually, which is usually set up by <sws:annotation-driven /> (one adapter with one JAXB marshaller):

 <bean class="org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter"> <property name="methodArgumentResolvers"> <list> <ref local="marshallingPayloadMethodProcessor"/> </list> </property> <property name="methodReturnValueHandlers"> <list> <ref local="marshallingPayloadMethodProcessor"/> </list> </property> </bean> <bean id="marshallingPayloadMethodProcessor" class="org.springframework.ws.server.endpoint.adapter.method.MarshallingPayloadMethodProcessor"> <property name="marshaller" ref="marshaller" /> <property name="unmarshaller" ref="marshaller" /> </bean> <bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"> <property name="contextPaths"> <list> <value>springws.model</value> </list> </property> </bean> 

This is a custom display:

 <bean class="springws.PathAndPayloadRootAnnotationEndpointMapping" /> 

And 2) you must create your own mapping

 public class PathAndPayloadRootAnnotationEndpointMapping extends PayloadRootAnnotationMethodEndpointMapping { @Override protected QName getLookupKeyForMessage(MessageContext messageContext) throws Exception { String urlPart = ""; QName payloadRootPart = super.getLookupKeyForMessage(messageContext); TransportContext transportContext = TransportContextHolder.getTransportContext(); if (transportContext != null) { WebServiceConnection connection = transportContext.getConnection(); if (connection != null && connection instanceof HttpServletConnection) { String requestURI = ((HttpServletConnection)connection).getHttpServletRequest().getRequestURI(); String contextPath = ((HttpServletConnection)connection).getHttpServletRequest().getContextPath(); urlPart = requestURI.substring(contextPath.length()); } } return new QName(payloadRootPart.getNamespaceURI(), urlPart + "/" + payloadRootPart.getLocalPart()); } @Override protected List<QName> getLookupKeysForMethod(Method method) { List<QName> result = new ArrayList<QName>(); RequestMapping rm = AnnotationUtils.findAnnotation(method.getDeclaringClass(), RequestMapping.class); String urlPart = rm == null || rm.value().length != 1 ? "" : rm.value()[0]; List<QName> methodPart = super.getLookupKeysForMethod(method); for (QName qName : methodPart) { result.add(new QName(qName.getNamespaceURI(), urlPart + "/" + qName.getLocalPart())); } return result; } } 

which continues org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping . And all he does is expand the keys (QNames of the root elements of the payload) of messages with information extracted from the URI of the endpoint. I used the Spring @org.springframework.web.bind.annotation.RequestMapping annotation for this, but someone, thinking that this is a hack, can create their own annotation.

So for the endpoint:

 @org.springframework.ws.server.endpoint.annotation.Endpoint @RequestMapping("/ws/SpmlReadOnly") public class Endpoint1 { @ResponsePayload @PayloadRoot(namespace = "urn:test", localPart = "method1Request") public Response2 method(@RequestPayload Request1 request) throws Exception { return new Response2("e1 m1"); } } 

key missing:

 namespace = urn:test localName = method1Request 

but this:

 namespace = urn:test localName = /ws/SpmlReadOnly/method1Request 

The protected QName getLookupKeyForMessage(MessageContext messageContext) ensures that the display URI does not depend on the context of the WAR application is deployed to.

+5
source

Source: https://habr.com/ru/post/925123/


All Articles