I am trying to build a simple SOAP web service (basic CRUD) using Grails with Apache Axis2 Plugin.
All works well with methods that have a simple return type (like String, int).
The problem is when I try to retrieve a domain class object:
class Hotel {
static mapping = {
datasource 'hotel'
table 'hotel'
version false
hotelId column:'id', insertable: false, updateable: false
hotelName column:'hotel_name', sqlType:'varchar', name:'hotelName'
}
Integer hotelId
String hotelName
static constraints = {
hotelId(max: 2147483647)
hotelName(size:1..100)
}
}
I have the following methods, inside my service class:
class HotelService {
static expose=['axis2']
boolean transactional = false
String sayHello(String name) {
return "Hello ${name}!"
}
Hotel soapGetHotel(int id){
return Hotel.get(id)
}
}
Executing a curl for soapGetHotel(int id) gives me this error:
| Error 2012-11-13 15:29:46,142 [http-bio-8080-exec-3] ERROR engine.AxisEngine - java.lang.RuntimeException: org.apache.axis2.AxisFault: Mapping qname not fond for the package: grails.validation
Message: java.lang.RuntimeException: org.apache.axis2.AxisFault: Mapping qname not fond for the package: grails.validation
Please, see bellow my soap-xml file:
<soap:Envelope
xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
soap:encodingStyle="http://www.w3.org/2003/05/soap-encoding">
<soap:Body xmlns:m="http://ws.com">
<m:soapGetHotel>
<m:id>13</m:id>
</m:soapGetHotel>
</soap:Body>
</soap:Envelope>
And the curl command:
curl --verbose --request POST --header "Content-Type: application/soap+xml" --data #gethotel.xml http://localhost:8080/wsexample/services/hotel
I believe it has to do with axis that cannot find the mapping for the object. I tried resolving the issue as it is described in the accepted answer here: Axis2 not returning own objects, but no luck, I still get the error.
I followed all steps described in the axis2 grails documentation .
Any thoughts on how to solve this?
Thank you.
The Axis plugin is a rather old one and it seems that it has not been updated for the last 3 years. I would suggest to use the CXF plugin al an alternative. In our projects this worked out great!
Related
We are using API Manager 2.1.0 with a distributed deployment (double gateways).
When we create a SOAP API using a soap endpoint, we get an error.
These are the steps we followed in the API creator web interface:
Create a new API 'I Have SOAP endpoint'
In the Design API we add all the information required and save
When saving, we have an error when importing the WSDL:
ERROR {org.wso2.carbon.apimgt.impl.utils.APIMWSDLReader} - Error occurred while getting the wsdl address location {org.wso2.carbon.apimgt.impl.utils.APIMWSDLReader}
java.net.MalformedURLException: no protocol: null/testphone/1.0
at java.net.URL.<init>(URL.java:593)
at java.net.URL.<init>(URL.java:490)
at java.net.URL.<init>(URL.java:439)
at org.wso2.carbon.apimgt.impl.utils.APIMWSDLReader.setServiceDefinition(APIMWSDLReader.java:307)
at org.wso2.carbon.apimgt.impl.utils.APIMWSDLReader.updateWSDL(APIMWSDLReader.java:156)
at org.wso2.carbon.apimgt.impl.utils.APIUtil.createWSDL(APIUtil.java:1375)
at org.wso2.carbon.apimgt.impl.APIProviderImpl.updateWsdl(APIProviderImpl.java:731)
at org.wso2.carbon.apimgt.impl.APIProviderImpl.updateAPI(APIProviderImpl.java:836)
at org.wso2.carbon.apimgt.impl.UserAwareAPIProvider.manageAPI(UserAwareAPIProvider.java:72)
at org.wso2.carbon.apimgt.hostobjects.APIProviderHostObject.saveAPI(APIProviderHostObject.java:1061)
at org.wso2.carbon.apimgt.hostobjects.APIProviderHostObject.jsFunction_updateAPIImplementation(APIProviderHostObject.java:672)
at sun.reflect.GeneratedMethodAccessor392.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.mozilla.javascript.MemberBox.invoke(MemberBox.java:126)
at org.mozilla.javascript.FunctionObject.call(FunctionObject.java:386)
and the WSDL imported (in the registry) has a null in the location in wsdl:port.
If we use only one gateway and import the same WSDL we do not have the error and everything works smoothly.
The problem is not related to the WSDL and it happens with all WSDL.
How can we solve it?
We have solved the problem. These are the steps we used following this link (https://wso2.org/jira/browse/APIMANAGER-5843) and (https://github.com/wso2/carbon-apimgt/pull/4301/commits/c9d38bd0864bc84b3d8f5731ccc6a49068448f33):
Download the source code of the version of your API Carbon Mgt and locate APIUtil.java (org.wso2.carbon.apimgt.impl/src/main/java/org/wso2/carbon/apimgt/impl/utils/APIUtil.java)
Find the method getGatewayendpoint(String transports) and replace it with this code lines:
public static String getGatewayendpoint(String transports) {
String gatewayURLs;
Map<String, Environment> gatewayEnvironments = ServiceReferenceHolder.getInstance()
.getAPIManagerConfigurationService()
.getAPIManagerConfiguration()
.getApiGatewayEnvironments();
if (gatewayEnvironments.size() > 1) {
for (Environment environment : gatewayEnvironments.values()) {
if (APIConstants.GATEWAY_ENV_TYPE_HYBRID.equals(environment.getType())) {
gatewayURLs = environment.getApiGatewayEndpoint(); // This might have http,https
// pick correct endpoint
return APIUtil.extractHTTPSEndpoint(gatewayURLs, transports);
}
}
for (Environment environment : gatewayEnvironments.values()) {
if (APIConstants.GATEWAY_ENV_TYPE_PRODUCTION.equals(environment.getType())) {
gatewayURLs = environment.getApiGatewayEndpoint(); // This might have http,https
// pick correct endpoint
return APIUtil.extractHTTPSEndpoint(gatewayURLs, transports);
}
}
for (Environment environment : gatewayEnvironments.values()) {
if (APIConstants.GATEWAY_ENV_TYPE_SANDBOX.equals(environment.getType())) {
gatewayURLs = environment.getApiGatewayEndpoint(); // This might have http,https
// pick correct endpoint
return APIUtil.extractHTTPSEndpoint(gatewayURLs, transports);
}
}
} else {
gatewayURLs = ((Environment) gatewayEnvironments.values().toArray()[0]).getApiGatewayEndpoint();
return extractHTTPSEndpoint(gatewayURLs, transports);
}
return null;
}
Locate org.wso2.carbon.apimgt.impl_6.1.66 and replace the class with the new APIUtil.java
Add this patch according to WSO2 documentation
Now you can publish on mutliple gateway
From Elixir, I am trying to call a SOAP Web Service with detergentex, which is a wrapper around the Erlang library detergent.
I can call the SOAP Web Service in the example on the detergent home page with no problems: http://www.webservicex.net/convertVolume.asmx?WSDL
Parameters:
wsdl_url = "http://www.webservicex.net/convertVolume.asmx?WSDL"
action = "ChangeVolumeUnit"
parameters = ["100","dry","centiliter"]
However when trying to call an Axis2 Java SOAP Web Service I am having some problems. Example: http://www.thomas-bayer.com/axis2/services/BLZService?wsdl
When calling "getBank" in the following way
wsdl_url = "http://www.thomas-bayer.com/axis2/services/BLZService?wsdl"
action = "getBank"
parameters = ["abc"]
wsdl = Detergentex.init_model(wsdl_url)
res = Detergentex.call(wsdl, action, parameters)
I get the following error message:
{:error, 'Struct doesn\'t match model: recordtype not expected: p:getBank'}
with the following stack trace
src/erlsom_write.erl:357: :erlsom_write.findAlternative/4
src/erlsom_write.erl:258: :erlsom_write.processSubType/5
src/erlsom_write.erl:241: :erlsom_write.processElementValues/7
src/erlsom_write.erl:132: :erlsom_write.struct2xml/6
src/erlsom_write.erl:323: :erlsom_write.processAlternativeValue/8
src/erlsom_write.erl:241: :erlsom_write.processElementValues/7
src/erlsom_write.erl:116: :erlsom_write.struct2xml/6
src/erlsom_write.erl:323: :erlsom_write.processAlternativeValue/8
src/erlsom_write.erl:241: :erlsom_write.processElementValues/7
src/erlsom_write.erl:45: :erlsom_write.write/2
src/detergent.erl:211: :detergent.call_attach/8
Any suggestions as to what I'm doing wrong?
According to the implementation a prefix is added on the init_model.
def init_model(wsdl_url, prefix \\ 'p') do
Detergentex.Client.init_model(wsdl_url, prefix)
end
I would suggest to add an empty prefix.
I am trying to use soap-ui 5.0.0. to make a call to web service using spnego-kerberos authentication.
I have followed:
http://www.soapui.org/SOAP-and-WSDL/spnego-kerberos-authentication.html
My login.conf:
com.sun.security.jgss.login {
com.sun.security.auth.module.Krb5LoginModule required
client=true;
};
com.sun.security.jgss.initiate {
com.sun.security.auth.module.Krb5LoginModule required
debug=true
useTicketCache=true
useKeyTab=true
keyTab="C:\\kerberos\\testuser.keytab"
principal=testuser#XX1.AD.XX.COM
doNotPrompt=true;
};
com.sun.security.jgss.accept {
com.sun.security.auth.module.Krb5LoginModule required
client=true
useTicketCache=true;
};
However, when I make the call I get the following error:
ERROR:java.lang.SecurityException: Configuration Error:
Line 11: expected [option key], found [null]
This seems to point to line 11 in login.conf:
keyTab="C:\\kerberos\\testuser.keytab"
ISSUE:
This is caused by line principal=testuser#XX1.AD.XX.COM.
It does not like the #XX1.AD.XX.COM, with principal=testuser, it proceeds further and but now I get authentication 401 error instead.
Please advise.
Thanks,
B.
Wrap the principal value with double quotes as for the keyTab.
principal="testuser#XX1.AD.XX.COM"
And it will work as desired.
Cheers,
Piotr
I created two grails project, one for server side cxf web service and other for cxf client for calling web service..
Everything works fine.
I can call web service from client code and get result.
Now I want to add security, then what will be the changes to server and client grails code?
I tried applying security as said by Christian Oestreich in his post.
http://www.christianoestreich.com/2012/04/grails-cxf-interceptor-injection/
(Grails Cxf Interceptor Injection 2.4.x-2.5.x)
and client code for applying security is as follows
ExampleService exampleService = new ExampleService()
def port = exampleService.exampleServicePort
Map ctx = ((BindingProvider)port).getRequestContext();
ctx.put("ws-security.username", "pankaj");
ctx.put("ws-security.password", "pankaj");
println ".......... " + port.sayHello("pankaj")
But I am getting error as follows
Error |
2014-11-06 18:33:15,411 [http-bio-8088-exec-4] ERROR errors.GrailsExceptionResolver - SoapFault occurred when processing request: [GET] /WSDLDemoClient/wsdldemo/index
An error was discovered processing the <wsse:Security> header.. Stacktrace follows:
Message: An error was discovered processing the <wsse:Security> header.
Line | Method
->> 75 | unmarshalFault in org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor
Instead of above mentioned client code, use following code to get it working.
Map<String, Object> req_ctx = ((BindingProvider)hello).getRequestContext();
req_ctx.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, WS_URL);
Map<String, List<String>> headers = new HashMap<String, List<String>>();
headers.put("Username", Collections.singletonList("pankaj"));
headers.put("Password", Collections.singletonList("pankaj"));
req_ctx.put(MessageContext.HTTP_REQUEST_HEADERS, headers);
I followed the advice provided here and it worked like a charm. Right now, I'm connecting to the server and calling a method named GetFunctionalityTest. The only input to it is a string, which can be seen in the GetFunctionalityTest.m file. So far so good.
Then I attempted to call the real service named GetSections whose signature according to the file GetSections.m is as follows.
function GetSectionsResult = GetSections(obj,auth)
% GetSections(obj,auth)
% Input: auth = (Authorize)
% Output: GetSectionsResult = (ArrayOfString)
values = { auth, };
names = { 'auth', };
types = { '{WSPro.HostingWebservice}Authorize', };
soapMessage = createSoapMessage( ...
'WSPro.HostingWebservice', ...
'GetSections', values,names,types,'document');
response = callSoapService( obj.endpoint, ...
'WSPro.HostingWebservice/GetSections', soapMessage);
GetSectionsResult = parseSoapResponse(response);
The definition provided by the server is as follows.
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi=...>
<soap:Body>
<GetSections xmlns="WSPro.HostingWebservice">
<auth>
<uid>string</uid>
<pw>string</pw>
</auth>
</GetSections>
</soap:Body>
</soap:Envelope>
My problem is that I can't specify the authorization syntax-wise. As far I understand, it's supposed to consist of two strings somehow but I haven't get it to work. I've tried to compound those as follows.
myAuthorization = ['user', 'pass'];
myAuthorization = {'user', 'pass'};
myAuthorization = ['user' 'pass'];
myAuthorization = {'user' 'pass'};
Nothing helped. I just got a bunch of errors.
Error using callSoapService (line 147)
Unspecified Fault: SOAP Fault: Server was unable to process request.
---> The parameterized query
'(#uid nvarchar(99)) SELECT PassW FROM UserData WHERE UserId = #' expects the parameter '#uid', which was not supplied.
I've browsed all the files automatically created for me and there's no definition of Authorize not ArrayOfString. I'm guessing it's something that the server defines, since I get no hits on those in MatLab documentation.
How can I specify the credentials for authorization?
Where can I look up how MatLab maps Authorization?
As noted above:
The SOAP Authentication happens through SOAP Header and not SOAP Body.This link might give you an idea of how SOAP XML should look in case of authentication :
Web service soap header authentication