Hi I am developing XML Soap services using WCF. My requirement is to update some database table. I have one method to update values in the db. Below is my service.
[ServiceContract]
public interface IOpportunity
{
[OperationContract]
[WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Xml, UriTemplate = "postmethod/updateOpportunity")]
bool updateOpportunity(opportunityActivity obj);
}
[DataContract]
public class opportunityActivity
{
[DataMember]
public string opportunityID { get; set; }
[DataMember]
public string opportunityStatus { get; set; }
[DataMember]
public string opportunityserviceType { get; set; }
}
Below is my xml.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:s="http://localhost:39512/Opportunity.svc">
<soapenv:Header/>
<soapenv:Body>
<s:request>
<opportunityID>1-1D5SJX</opportunityID>
<opportunityStatus>Completed</opportunityStatus>
<opportunityserviceType>LEASE_REQUEST</opportunityserviceType>
</s:request>
</soapenv:Body>
</soapenv:Envelope>
when i i try as shown above i get 400 bad request error.May i know am i following correct approach to test the service? Can someone correct me if i am doing wrong? Any help would be greatly appreciated. Thank you.
You have to pass a soap message to the service endpoint.
Eg
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:s="http://myNamespace/">
<soapenv:Header/>
<soapenv:Body>
<s:request>
....
</s:request>
</soapenv:Body>
</soapenv:Envelope>
To get hold of a soap message you should use the service endpoint definition and use some tooling to generate a valid request.
Additionally, you should not be sending data to the endpoint address with ?wsdl as part of the address. It should only be the endpoint address.
Related
I am new to java web service. I want to add headers to my web service I tried to add #WebParam(name = "noun", header = true) in my input parameters of web method. I tried something like . I need an example with the below XML format of output. Can someone please help me to add the authentication info in header part.
// Sample XML
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.reports.cfr.nesl.com/">
<soapenv:Header>
<AuthenticationInfo>
<userName>User</userName>
<password>password<password/>
</AuthenticationInfo>
</soapenv:Header>
<soapenv:Body>
<ser:getCreditFacilReport>
<arg0>
<!--Optional:-->
<info_type>?</info_type>
<!--Optional:-->
<info_value>?</info_value>
<!--Optional:-->
<output_type>?</output_type>
<!--Optional:-->
<requester_pan>?</requester_pan>
</arg0>
</ser:getCreditFacilReport>
</soapenv:Body>
</soapenv:Envelope>
===========The below java code which i have without header param==================
// Service implements calss
#WebService(endpointInterface = "com.nesl.cfr.reports.service.CreditFacilReportService")
public class CreditFacilReportServiceImpl implements CreditFacilReportService
{
#Override
public CreditFacilReportResponseBean getCreditFacilReport(CreditFacilReportRequestBean requestbean)
{
/*
....
....
*/
}
}
//Service class
#WebService
#SOAPBinding(style=SOAPBinding.Style.RPC)
public interface CreditFacilReportService {
#WebMethod
public CreditFacilReportResponseBean getCreditFacilReport(CreditFacilReportRequestBean requestbean);
}
I'm trying to set up empty target namespace when creating the Web Service. Here is the example. My service looks like this:
package com.example;
import javax.jws.WebMethod;
import javax.jws.WebService;
#WebService
public class SampleService
{
#WebMethod
public void sampleMethod()
{
}
}
Defined like that, it accepts requests that look like this (please note the exam namespace declaration):
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:exam="http://example.com/">
<soapenv:Header/>
<soapenv:Body>
<exam:sampleMethod/>
</soapenv:Body>
</soapenv:Envelope>
I would like to configure the web service to accept the requests that look like this (without the namespace):
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<sampleMethod/>
</soapenv:Body>
</soapenv:Envelope>
I tried to set up the targetNamespace to the empty string, but that didn't work - it just defaulted to the exam namespace.
#WebService(targetNamespace="")
I'm using Apache CXF (3.1.0) to expose the service:
<bean id="sampleService" class="com.example.SampleService" />
<jaxws:endpoint id="sampleServiceWs" implementor="#sampleService"
address="/SampleService" publish="true">
</jaxws:endpoint>
To answer my question - I didn't find a way to set the empty targetNamespace, but I managed to leave out the request validation on my service, so that it now accepts the request with the namespace also. To do that, I used the #EndpointProperty annotation on top of the service class:
package com.example;
import javax.jws.WebMethod;
import javax.jws.WebService;
import org.apache.cxf.annotations.EndpointProperty;
#WebService
#EndpointProperty(key = "soap.no.validate.parts", value = "true")
public class SampleService
{
#WebMethod
public void sampleMethod()
{
}
}
The web service that calls us expects us to return the following XML:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:loc="http://www.csapi.org/schema/parlayx/sms/notification/v2_2/local">
<soapenv:Header />
<soapenv:Body>
<loc:notifySmsDeliveryReceiptResponse />
</soapenv:Body>
</soapenv:Envelope>
We use JAX-WS to provide our web service. The following is how we define our web service interface:
#BindingType(value = javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_MTOM_BINDING)
#WebService (targetNamespace = "http://www.csapi.org/schema/parlayx/sms/notification/v2_2/local")
#HandlerChain(file = "deliverysoaphandler.xml")
#SOAPBinding(style = Style.DOCUMENT)
public interface DeliveryService {
#WebMethod ()
public void notifySmsReception(
#WebParam(name = "correlator", targetNamespace = "http://www.csapi.org/schema/parlayx/sms/notification/v2_2/local") #XmlElement(required = true) String correlator,
#WebParam(name = "message", targetNamespace = "http://www.csapi.org/schema/parlayx/sms/notification/v2_2/local") #XmlElement(required = true) Message message
) throws DeliveryException;
}
This produces the following return document:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<S:Body>
<ns2:notifySmsReceptionResponse xmlns:ns2="http://www.csapi.org/schema/parlayx/sms/notification/v2_2/local"/>
</S:Body>
</S:Envelope>
We think the document is essential the same as what the calling system expects but gets rejected because 1) the namespaces are capitalized, 2) the same namespace reference is repeated and 3) there is a namespace declaration in the middle of the document.
Is there anyway in which I can persuade the JAX-WS provider to produce what the other system wants?
Based on this description, I am not sure the namespaces are the problem.
The service consumer is expecting:
<soapenv:Body>
<loc:notifySmsDeliveryReceiptResponse />
</soapenv:Body>
but is receiving
<S:Body>
<ns2:notifySmsReceptionResponse xmlns:ns2="..."/>
</S:Body>
which indicates a response to a different operation name.
Try changing your service endpoint interface WebMethod method name to:
#WebMethod ()
public void notifySmsDeliveryReceipt(
Doing so will require you to also change the method name on the implementation class (or it will no longer compile).
Alternatively, you can also just change your #WebMethod to the desired/indicated operation name:
#WebMethod (operationName="notifySmsDeliveryReceipt")
public void notifySmsReception(
The service should now produce:
<S:Body>
<ns2:notifySmsDeliveryReceiptResponse xmlns:ns2="http://www.csapi.org/schema/parlayx/sms/notification/v2_2/local"/>
</S:Body>
I'm working on custom axis2 module for wso2 esb. Right now I'm using code from https://docs.wso2.com/display/ESB490/Writing+an+Axis2+Module
and I have a problem with incoming requests. It doesn't matter what request I send because it always looks like this:
<?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body/></soapenv:Envelope>
On the other hand OutFlow works more or less as it should - response looks ok but instead of "out" its direction is set as "in". If I'm not mistaken invoke method will be called for requests and revoke for responses - am I right? In my case both are using invoke. Any ideas what I'm doing wrong?
Edit:
My handler code:
public class LogHandler extends AbstractHandler implements Handler {
private Logger log = Logger.getLogger(LogHandler.class.toString());
#Override
public void init(HandlerDescription handlerDescription) {
super.init(handlerDescription);
}
public InvocationResponse invoke(MessageContext msgContext) throws AxisFault {
System.out.println("invoked: " + msgContext.getEnvelope().toString() + "\n");
log.info("invoked: " + msgContext.getEnvelope().toString() + "\n");
return InvocationResponse.CONTINUE;
}
public void revoke(MessageContext msgContext) {
log.info("revoked: " + msgContext.getEnvelope().toString() + "\n");
}
}
Module:
public class LoggingModule implements Module {
private static final Log log = LogFactory.getLog(LoggingModule.class);
// initialize the module
public void init(ConfigurationContext configContext, AxisModule module) throws AxisFault {
}
public void engageNotify(AxisDescription axisDescription) throws AxisFault {
}
// shutdown the module
public void shutdown(ConfigurationContext configurationContext) throws AxisFault {
}
public String[] getPolicyNamespaces() {
return null;
}
public void applyPolicy(Policy policy, AxisDescription axisDescription) throws AxisFault {
}
public boolean canSupportAssertion(Assertion assertion) {
return true;
}
}
module.xml:
<module name="sample-logging" class="pl.wso2.logging.LoggingModule">
<InFlow>
<handler name="InFlowLogHandler" class="pl.wso2.logging.LogHandler">
<order phase="loggingPhase"/>
</handler>
</InFlow>
<OutFlow>
<handler name="OutFlowLogHandler" class="pl.wso2.logging.LogHandler">
<order phase="loggingPhase"/>
</handler>
</OutFlow>
</module>
In my wso2 proxy I use Payload Mediator to create response and then return it using Respond Mediator.
For given request:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<aa>blahblah</aa>
</soapenv:Body>
</soapenv:Envelope>
there two thing logged:
request from InFlow
invoked: <?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlso
ap.org/soap/envelope/"><soapenv:Body/></soapenv:Envelope>
and response from OutFlow
invoked: <?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlso
ap.org/soap/envelope/"><soapenv:Body><m:checkpriceresponse xmlns:m="http://services.samples/xsd"><m:
code>dsadsa</m:code></m:checkpriceresponse></soapenv:Body></soapenv:Envelope>
As per https://axis.apache.org/axis2/java/core/docs/modules.html#Step2_:_LogHandler ...
"public void invoke(MessageContext ctx);" is the method that is called
by the Axis2 engine when the control is passed to the handler. "public
void revoke(MessageContext ctx);" is called when the handlers are
revoked by the Axis2 engine."
which means since you are calling same handler in both InFlow and OutFlow the same invoke() method should be getting triggered for both the request and the response. If you want different logics to be executed for requests and responses maybe you should write separate handlers for request and response.
After debugging everything I've found that while request was parsed in InFlow, instead of using its soap message, new one (empty) was created. Thankfully it's possible to access proper request using soap tracer handler (or just its code).
I have configured my WebService like this:
applicationContext:
<sws:annotation-driven />
<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping" >
<property name="interceptors">
<list>
<bean class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor"/>
</list>
</property>
Note: the Interceptor is loaded on startup, but doesn´t write anything, if a request is coming in.
I have a class PersonServiceImpl with the method addPersonRequest(). Everything works , if i am using org.dom4j.Element as method parameter;
#Endpoint
public class PersonServiceImpl {
#PayloadRoot(namespace = "http://www.example.org/person/schema", localPart = "AddPersonRequest")
#ResponsePayload
public AddPersonRequest addPersonRequest(#RequestPayload Element element) {
System.out.println(element.asXML());
Person response = new Person();
response.setId(2);
response.setFirstName("Mad");
response.setLastName("Mike");
return response;
}
}
But if i change my method parameters like shown below (so auto-marshalling of spring-ws should be used) the request.getFirstName() prints null. (JAXB2 is on classpath).
The Person-class is annotated with #XMLType and #XMLRootElement.
Note: The marshalling works fine.
#Endpoint
public class PersonServiceImpl {
#PayloadRoot(namespace = "http://www.example.org/person/schema", localPart = "AddPersonRequest")
#ResponsePayload
public AddPersonRequest addPersonRequest(#RequestPayload Person request, SoapHeader header) {
System.out.println(header.getName());
System.out.println(request.getFirstName());
Person response = new Person();
response.setId(2);
response.setFirstName("Mad");
response.setLastName("Mike");
return response;
}
}
Person.java:
#XmlType
#XmlRootElement(namespace="http://www.example.org/person/schema", name="Person")
public class Person implements Serializable {
private int id;
private String firstName;
private String lastName;
#XmlElement
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
#XmlElement
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
#XmlAttribute
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
Test-Request sent via soapUI (generated from wsdl):
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sch="http://www.example.org/person/schema">
<soapenv:Header/>
<soapenv:Body>
<sch:AddPersonRequest>
<sch:Person sch:Id="1">
<sch:FirstName>firstname</sch:FirstName>
<sch:LastName>lastname</sch:LastName>
</sch:Person>
</sch:AddPersonRequest>
</soapenv:Body>
</soapenv:Envelope>
I'm not sure if you still need an answer, reading your latest comment. I'm a bit confused with your request and response payload. They seem to be switched. Anyway, that's hard to say without the Person class.
I've dealt with similar issues before though and those were solved by adding JAXBElement<> around the actual class. Like this snippet:
#PayloadRoot(
localPart = "PutOrganisationUnitRequest",
namespace = DEFAULT_NAMESPACE
)
#ResponsePayload public JAXBElement<Response> putOrganisationUnits (
#RequestPayload JAXBElement<PutOrganisationUnitRequest> organisations,
MessageContext messageContext) {
One other thing you can check is the namespaces in your jaxb class and in your endpoint definition.
You mentioned marshalling is working I don't see any reason why unmarshalling won't work, Have you tested marshall and unmarshall in isloation?
Just to make sure the soap request is good, Can you add logging interceptor and print the actual request that is coming from the client accessing web service, Add this snippet to your context file
<sws:interceptors>
<bean class="org.springframework.ws.soap.server.endpoint.interceptor.SoapEnvelopeLoggingInterceptor">
<property name="logRequest" value="true"></property>
<property name="logResponse" value="true"></property>
</bean>
</sws:interceptors>
You should see a log message like this that contains the entire soap request, I am adding a log message request from a saop UI to
DEBUG [http-8080-2]:endpoint.interceptor.SoapEnvelopeLoggingInterceptor.logMessage - Request:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sch="http://hoost:port/context/patient/schemas">
<soapenv:Header/>
<soapenv:Body>
<sch:addRequest>
<sch:patient>
<sch:id>?</sch:id>
<sch:lastname>Joe</sch:lastname>
</sch:patient>
</sch:addRequest>
</soapenv:Body>
</soapenv:Envelope>
UPDATE of answer
It could be your soap request not sure though
<sch:FirstName>firstname</sch:FirstName> (this should be)
<sch:firstName>firstname</sch:firstName>
Another update
The exception is due to the way you defined the end point, In your soap request (sch:AddPersonRequest) you are sending a addPersonRequest not Person as payload so change the end point to reflect that, The #RequestPayload should be AddPersonRequest not Person
#PayloadRoot(namespace = "http://www.example.org/person/schema", localPart = "AddPersonRequest")
#ResponsePayload
public AddPersonRequest addPersonRequest(#RequestPayload AddPersonRequest request, SoapHeader header) {
This Spring webservice implementation is utter garbage. A brain dead idiot could do work better than those "pros".
How hard it was to just follow the JSON principles and restore object tree following offered root type.
NO-ONE needs these namespaces. It never happens that the same request have two elements with the same name but from different namespaces. But these namespaces is endless pain.
Just match XML elements to object fields. This only what is required. Assign namespaces from WSDL when generating responses if anyone cares them on retrieving end but completely ignore them when unmarshaling a request.
When I look at all of this I really want to spend a month and do a NORMAL SOAP webservice framework with XML serialization/deserialization that only cares about element names and auto instantiate request/response objects as long as XML tree is matching object tree.