I have a JAX-RPC web service that I am attempting to consume using Spring. This is my first time using Spring to consume a web service, so right now I'm just trying to get it to integrate with the JAX-RPC web service as a test.
The web service has several dozen operations in it, but for right now I only care about one. Here are the interfaces I've created on the Spring/client side:
public interface WSClient {
public boolean userExists(int userid);
}
public interface WSService {
//this method matches the method signature of the Web Service
public com.company.data.User getUser(int userid);
}
And here is my applicationContext.xml:
<bean id="WSClient" class="com.company.ws.test.WSClientImpl">
<property name="service" ref="myWebService"></property>
</bean>
<bean id="myWebService" class="org.springframework.remoting.jaxrpc.JaxRpcPortProxyFactoryBean">
<property name="serviceInterface" value="com.company.ws.test.WSService"/>
<property name="endpointAddress" value="http://1.2.3.4/web-service/data"/>
<property name="namespaceUri" value="http://www.company.com/wdsl"/>
<property name="serviceName" value="CompanyWebService"/>
<property name="username" value="username"/>
<property name="password" value="password"/>
<property name="maintainSession" value="true"/>
</bean>
Using this configuration of JaxRpcPortProxyFactoryBean, invoking the Service returns the following exception:
org.springframework.remoting.RemoteProxyFailureException: Invalid JAX-RPC call configuration; nested exception is operation style: "rpc" not supported
I've never fully understood the difference between RPC and document-style web services; however, I believe this web service is using RPC-style - so this exception confuses me.
Second, I'm confused on which properties I should be setting with JaxRpcPortProxyFactoryBean:
If I set the wsdlDocumentUrl property, I end up getting a HTTP 401 error as this web service sits behind HTTP Basic Authentication, and it seems Spring does not use the username/password properties when fetching the WSDL.
If I specify a PortInterface property (with a value of CompanyWebServiceInterfacePort), then I get a different Exception stating:
Failed to initialize service for JAX-RPC port [{http://www.company.com/wdsl}CompanyWebServiceInterfacePort]; nested exception is WSDL data missing, this operation is not available
In other words, it's telling me that the WSDL is missing - which I can't set since Spring won't use the username/password to fetch it from the server!
I'm not sure if any of this makes any sense, but in essence what I'm unsure of is:
For a JAX-RPC service, do I need to set the PortInterface property? Is this the path I should be going down?
Similiarly, does Spring need me to set the wsdlDocumentUrl property? If so, is there any way I can tell Spring which WSDL and get around the authentication problem?
I eventually solved this by saving a copy of the WSDL file locally, and, since JaxRpcPortProxyFactoryBean expects a java.net.URL for the wsdlDocumentUrl property, had to set it with a path like file:///c:/.../blah.wsdl.
This isn't really all that desireable, I would hate to have to put a file:/// URI in a Spring context file that might be deployed on a server, especially on a different platform - seems odd that this class behaves this way.
I'm guessing most people aren't using Spring aren't using JAX-RPC anyway.
Related
I'm trying to inject the EJB with a Spring application in a Websphere server to call his methods.
I downloaded the EJB's jar and added it as a Library in the project.
The jar exposes a Remote, which is an interface.
1: EJB Jar in Libraries
Then I tried to make Spring understand that it is an EJB.
I put this inside web.xml
<description />
<ejb-ref-name>ejb/AberturaEJBRemoteRef</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<home />
<remote>
br.com.zzz.xxx.servcaptura.abertura.ejb.AberturaEJBRemote
</remote>
<ejb-link>AberturaEJB</ejb-link>
</ejb-ref>
Then I tried these two configurations at app.context:
First attempt:
<jee:remote-slsb id="abertura" jndi- name="ejb/AberturaEJBRemoteRef#br.com.zzz.xxx.servcaptura.abertura.ejb.AberturaEJBRemote"
business-interface="br.com.zzz.xxx.servcaptura.abertura.ejb.AberturaEJBRemote"
home-interface="br.com.zzz.xxx.servcaptura.abertura.ejb.AberturaEJBRemote"
cache-home="false" lookup-home-on-startup="false"
refresh-home-on-connect-failure="true" />
Second attempt:
<bean id="abertura"
class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean" lazy-init="true">
<property name="jndiName" value="ejb/AberturaEJBRemoteRef" />
<property name="businessInterface" value="br.com.zzz.xxx.servcaptura.abertura.ejb.AberturaEJBRemote" />
</bean>
<bean id="acompanhamentoWebService" class="br.com.zzz.xxx.integracaosinistro.servacompws.webservice.AcompanhamentoWebService">
<property name="abertura">
<ref bean="abertura" />
</property>
</bean>
Inside a class, I'm doing this:
#Service
#WebService
public class AcompanhamentoWebService {
#Autowired(required = true)
private AberturaEJBRemote abertura;
...
The second one Spring can't understand that it is a bean.
On the first configuration attempt, with jee:remote-slsb, here I'm getting error after call the EJB method:
name: ejb/AberturaEJBRemoteRef#br.com.zzz.xxx.servcaptura.abertura.ejb.AberturaEJBRemote: First component in name AberturaEJBRemoteRef#br.com.zzz.xxx.servcaptura.abertura.ejb.AberturaEJBRemote not found. [Root exception is org.omg.CosNaming.NamingContextPackage.NotFound: IDL:omg.org/CosNaming/NamingContext/NotFound:1.0]
I really don't know if I am trying this correctly, cause I never work with EJB before.
Call the remote inside the jar is a correct approach?
What do you think I'm doing wrong?
Sorry for the bad English.
Thanks.
UPDATE
I founded an example and it seems that my approach is ok. But it missing an EJB configuration inside Websphere. To call the EJB remotely, I read that I will need the server informations where the EJB is stored and available.
And I don't have this information yet.
I think that I could access the methods from EJB directly from the jar. But I understood that it's not like this.
I will come back here when the problem was solved or another information appears.
We are developing a Spring application which run on JBoss. I've just discovered a problem with characters encoding and #ModelAttribute and #RequestBody annotations when we are sending requests via GET method described in:
Encoding problem using Spring MVC
http://forum.spring.io/forum/spring-projects/web/74209-responsebody-and-utf-8
and possible solution:
http://wiki.apache.org/tomcat/FAQ/CharacterEncoding#Q2
https://developer.jboss.org/message/643825#643825
https://docs.jboss.org/jbossweb/2.1.x/config/http.html
In general we added:
<system-properties>
<property name="org.apache.catalina.connector.URI_ENCODING" value="UTF-8"/>
<property name="org.apache.catalina.connector.USE_BODY_ENCODING_FOR_QUERY_STRING" value="true"/>
to standalone.xml file on JBoss and this solved the issue.
We just thinking if there is any possibility to keep this properties in our application and use them when needed instead of changing JBoss configuration? Or maybe you know other working solution on the application side instead of server side?
I am using Spring, Spring Security, CAS login and Maven in my web application.
At the time of CAS (central authentication service) login I need service URL in config file.
Can I get server URL or base URL of my application in Spring Security XML config file without hard code on any other place?
If I understand the Spring Security Reference right, you have to write the URL into the configuration:
<bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
<property name="service" value="https://localhost:8443/cas-sample/j_spring_cas_security_check"/>
<property name="sendRenew" value="false"/>
</bean>
If I understand ServiceProperties#getService right, it don't support relativ URLs.
Represents the service the user is authenticating to.
This service is the callback URL belonging to the local Spring Security System for Spring secured application. For example,
https://www.mycompany.com/application/login/cas
In general, you don't know the URL until you get a request, see ServletRequest#getLocalName:
Returns the host name of the Internet Protocol (IP) interface on which the request was received.
First a bit of setup info:
I have a multi-tenant spring based application. The multi-tenant enabling library is an in-house developed tool where I work that I have to use. How it works is that there is an interceptor that sets in front of the servlet for the application. Upon a request hitting the servlet it loads a tenant specific spring config for "stuff" needed for the tenant specified on the url hitting the servlet.
As stated, the above is just a bit of background. Now to the issue/question:
What I want to do is to create, in the tenant configuration that is loaded, a value that I can use to inject where I need. So, is there a way I can just define a constant in a spring config and then reference it via #Value or #Resource in java code?
There will be no bean implementation behind it, it would just be purely and only a key/value that I can reference where needed in my application by name. So, something to the effect of:
<bean name="MyIdentifier">
<property name="theId" value="1001" />
</bean>
And then can I do something like?
#Value{MyIdentifier.theId}
String theId;
And have Spring be aware of and inject the value. The problem is that doing something like above Spring complains there is no implementation for the bean. Notice, no class specified for the bean. The reason I want to do this is every tenant config file will contain this bean, but the actual value will vary per tenant.
Is there some other type to use in the config to do this? If so, what schemas have to be on the config?
I am guessing I am either trying to make Spring do something not intended, or, this is so simple I cannot see it since I have stared at it too long. Anyway, thanks for the help.
You can not create bean tag in configuration file without providing class implementation. If you want to inject the value of fields, you have to go for properties file instead.
Create property file as below:
application.properties
theId=1001
Load property file in your configuration:
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="locations">
<list>
<value>classpath:application.properties</value>
</list>
</property>
</bean>
And access the property in your concrete class:
#Value("${theId}")
String theId;
I'm currently learning EclipseLink and Spring 3.0 MVC:
I wrote a simple standalone application using EclipseLink : it uses a META-INF/persistence.xml file and it reads and writes data from a mysql database.
I also wrote a simple 'HelloWorld' application using Spring3 MVC under apache tomcat. It is based on the following tutorial: http://www.mkyong.com/spring-mvc/spring-3-rest-hello-world-example
now, how should I link both technologies ? As far as I understand from http://static.springsource.org/spring/docs/3.0.0.M3/spring-framework-reference/html/ch14s06.html I need to create a LocalContainerEntityManagerFactoryBean:
<bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="someDataSource"/>
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
</property>
</bean>
but what is "someDataSource" ? should I use another library like http://commons.apache.org/dbcp/ ? then what should I do with eclipselink ?
And once the JPA will be configured, how should I access it from my spring Controller ?
Thank you
someDataSource would just be another bean, for example:
<bean id="someDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
Here I'm also using a property replacement for the properties, this is designated by the following bean:
<context:property-placeholder location="classpath:properties/runtime.properties" />
Since context is under a different xml namespace add:
xmlns:context="http://www.springframework.org/schema/context"
to your XML namespaces, and
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
to your schemaLocation string within the bean xml document.
classpath:properties/runtime.properties
This property file would be found at the following location in a standard Maven setup:
src/main/resources/properties/runtime.properties
Within this runtime.properties file you'd need to define values for each of the properties that have placeholders (i.e. jdbc.driverClassName, jdbc.url, etc.). An example of this would be:
jdbc.driverClassName=com.mysql.jdbc.Driver
If you're using MySQL for your database.
Generally speaking, you might want a service layer between your controller and repository (DAO). The reason being is controller should concentrate only on handling requests, and responding. Any business logic should be done in a different layer, through business objects, etc. Service layer acts as an intermediary between web layer, and repository layer. This not only separates concerns, but also makes things infinitely more unit testable, a huge part of any Spring application (at least it should be!).
As to how to wire things up, try inserting this bean into your Context as well:
<context:component-scan base-package="xx.yy..." />
Where xx and yy are your package names, this will tell Spring to scan your packages for "components" or #Controller objects, #Service, and #Repository (there are a few other ones but those are the main things to know about). With this information provided to Spring, you can #Autowire beans (dependency inject) into other beans.
For example:
#Service
public class SomeServiceImpl implements SomeService
{
private SomeRepository someRepository;
#Autowired
public void setSomeRepository(SomeRepository someRepository)
{
this.someRepository = someRepository;
}
...
}
This will inject the repository into the service allowing you to access that repositories methods.
Another design tip, always program for interfaces in Spring. This is especially true when it comes to repositories due to the fact that early in development, you might want to implement a Hibernate repository, but down the line DBAs might scoff at that, and require a JDBC repository using straight SQL. This way, you just need to implement the Repository using a JDBC approach rather than Hibernate, inject the JDBC repository instead of Hibernate, and you're done.
Hope this gets you started!