I'm using spring and in my client, a web app, I need to interact with a Jax-WS webservice. I currently have it working via annotating the service interface with the #WebServiceRef annotation. However, I need the wsdlLocation property to be injected because, obviously Sun Microsystems or Oracle, the web service wsdl location in production will be different to what's being used during development.
How can I inject the wsdlLocation?
Here's an extremely simplified version of the code:
//This client service lives in the web app. wsimport used to generate artifacts.
#Component
public class MyClientServiceImpl implements MyClientService {
#WebServiceRef(wsdlLocation = "http://localhost:8080/ws/MyOtherService/the.wsdl", value = MyOtherServiceService.class)
//Interface generated by wsimport
private MyOtherService otherService;
#Override
public List<SomeSearchData> search(String searchString) {
return otherService.search(searchString);
}
}
This is semi outlined in the JAX-WS FAQ. You need to inject the endpoint string as a standard member variable and then use...
((BindingProvider)proxy).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, this.injectedEnpointURL);
You can use LocalJaxWsPortProxyFactoryBean. You can configure WSDL URL (among other things) via this factory bean. Here is a configuration snippet from the official documentation:
<bean id="accountWebService" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
<property name="serviceInterface" value="example.AccountService"/>
<property name="wsdlDocumentUrl" value="http://localhost:8888/AccountServiceEndpoint?WSDL"/>
<property name="namespaceUri" value="http://example/"/>
<property name="serviceName" value="AccountService"/>
<property name="portName" value="AccountServiceEndpointPort"/>
</bean>
Then you can let Spring autowire this dependency into your target bean (e.g. MyClientServiceImpl).
Related
I am using a third party library in my application to do some task. They have provided a wrapper that I've added in my project using maven. For using this wrapper we have to give an access key to their client class in order to use it's functionality. For ex:
final WeatherApiService was = new WeatherApiServiceImpl(accessKey);
final WeatherApiClient weatherApiClient = new WeatherApiClient(was);
What I want is to remove the above code (Since it's kind of Singleton and should be registered in spring context when the application is being started) and do something so that I can just autowire the WeatherApiClient and we are good to go. (wrapper isn't using spring FYI). Below is what I did is in my spring context I registered two beans and put the access-key is web.xml.
spring-context.xml
<bean id="was" class="my.librarypath.WeatherApiService ">
<constructor-arg type="java.lang.String" value="${accessKeyFromWebXml}"/>
</bean>
<bean id="weatherApiClient" class="my.librarypath.WeatherApiClient">
<constructor-arg type="my.librarypath.WeatherApiService" value="was"/>
</bean>
my component that will use the third party library
#Component("myComponent")
public class MyComponent IComponent {
#Resource(name = "weatherApiClient") // <--- getting Error here i.e: Couldn't aurtowire, bean should be of String type
private String weatherApiClient;
public void myFunction() {
weatherApiClient.getWeather();
}
}
Can someone confirm if I'm doing it right or is there any best practices options available !?
Ther were two issues:
<bean id="weatherApiClient" class="my.librarypath.WeatherApiClient">
<constructor-arg type="my.librarypath.WeatherApiService" value="was"/>
// ^---- should be ref
</bean>
Secondly, I was using String instead of WeatherApiClient. MY BAD :/
#Resource(name = "weatherApiClient")
private String weatherApiClient;
// ^---- this one should have to be WeatherApiClient
I'm trying to add BouncyCastle to my Spring application but I am not sure how to add the provider to the java.security.Security provider list using JavaConfig.
Using XML configuration, I can use the MethodInvokingFactoryBean similar the following:
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="java.security.Security.addProvider"/>
<property name="arguments">
<list>
<bean class="org.bouncycastle.jce.provider.BouncyCastleProvider"/>
</list>
</property>
</bean>
However, I'm not sure of the right way to do this using JavaConfig. Should I still be using the MethodInvokingFactoryBean? I presumed since it is pure java, there would be a more direct approach. At the moment, I've added the directive to a #PostConstruct method in the JavaConfig object, but not too thrilled about it - it seems a little "hacky" to me:
#Configuration
public class AppConfig {
// other #Bean definitions
#PostConstruct
public void init(){
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}
}
MethodInvokingBean will be the de facto choice for add BouncyCastleProvider to java.security.Security since you won't need any exposure to your application context.
I've made a mavenized web application with spring, spring security... Now, I want to add ejb module for database access, I was looking on the internet but I didn't find something clear because it's my first time with EJB.
I want to use something like #EJB in my controller
like"
#Stateless(name = "CustomerServiceImpl")
public class CustomerServiceImpl implements CustomerService
#EJB
private MyEjb myEjb;
and how can I configure it in spring context if there is a tutorial or any other help. It will be great and thank you
To inject your ejb 3 bean in spring bean you can follow below steps.
1. Create your Spring bean
2. Create your EJB with its Remote and Local Interface
3. Write Implementations class
e.g.
package com.ejb;
#Local
public interface MyEjbLocal{
public String sendMessage();
}
package com.ejb;
#Remote
public interface MyEjbRemote{
public String sendMessage();
}
#Stateless(mappedName = "ejb/MessageSender")
public class MyEjbImpl implements MyEjbLocal, MyEjbRemote{
public String sendMessage(){
return "Hello";
}
}
above is the example of EJB3 which uses both remote and local interface
Now we create the Spring bean in which we inject this ejb.
package com.ejb;
#Service
public class MyService {
private MyEjbLocal ejb;
public void setMyEjbLocal(MyEjbLocal ejb){
this.ejb = ejb;
}
public MyEjbLocal getMyEjbLocal(){
return ejb;
}
}
We have added the instance of ejb in spring however we need to inject this in spring's spring-config.xml.
There are 2 ways to inject the ejb in spring bean
First Way
<bean id ="myBean" class="org.springframework.ejb.access.LocalStetelessSessionProxyFactoryBean">
<property name="jndiName" value="ejb/MessageSender#com.ejb.MyEjb=Local />
<property name="businessInterface" value="com.ejb.MyEjbLocal" />
</bean>
Note: I have used the Local interface here you can use Remote as per your need.
Another way of injecting the ejb is
<jee:remote-slsb id="messageSender"
jndi-name="ejb/MessageSender#com.ejb.MyEjbLocal"
business-interface="com.ejb.MyEjbLocal"
home-interface="com.ejb.MyEjbLocal"
cache-home="false" lookup-home-on-startup="false"
refresh-home-on-connect-failure="true" />
So when the bean get initialized at that time the ejb will get injected in your spring bean.
Have a look here: http://docs.spring.io/spring/docs/4.1.0.BUILD-SNAPSHOT/spring-framework-reference/htmlsingle/#ejb-access-local
You can inject EJB using setter injection. Configure your bean this way:
<bean id="myComponent" class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean">
<property name="jndiName" value="ejb/myBean"/>
<property name="businessInterface" value="com.mycom.MyComponent"/>
</bean>
<bean id="myController" class="com.mycom.myController">
<property name="myComponent" ref="myComponent"/>
</bean>
You can also use <jee:local-slsb> tag to be able to inject your EJB:
<jee:local-slsb id="myComponent" jndi-name="ejb/myBean"
business-interface="com.mycom.MyComponent"/>
<bean id="myController" class="com.mycom.myController">
<property name="myComponent" ref="myComponent"/>
</bean>
I've followed the tutorial for spring remoting, in particular HttpInvokerServiceExporter and have no problems setting up both the client and the server (factorybean).
Question is, I've noticed using Spring MVC, each interface is mapped to a particular URL
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="hello.htm">test_service</prop>
</props>
</property>
</bean>
<!-- *********************exposed web services*************************-->
<bean name="test_service" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
<property name="serviceInterface" value="foo.webservices.HelloServiceInterface" />
<property name="service">
<ref bean="helloService"></ref>
</property>
Question is, if I have more than 1 method in my service interface, is it possible to map each of these interface methods to a URL themselves?
The idea behind HTTPInvokerServiceExporter is to provide an endpoint to receive remove method invocation.
On the server side it would be easy as configure a RemoteExporter, declaring the interface you want to expose and associating it to the real bean that will handle the invocations.
On the client it would be necessary configure the RemoteAcessor that basically needs the interface that is going be access on the server side.
The implementation over HTTP can be done using HttpInvokerServiceExporter on the server side like the following example:
Service Interface:
package foo.bar.services;
public interface MyService {
public int sum(int num1, int num2);
}
For this service you would have an implementation (let's say foo.bar.services.DefaultMyService).
The exposition and configuration on spring context would look like:
<bean name="myService" class="foo.bar.DefaultMyService" />
<bean name="/myService" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
<property name="service" ref="myService"/>
<property name="serviceInterface" value="foo.bar.MyService"/>
</bean>
With this configuration I just intended to have a instance of my implementation of MyService being exposed under foo.bar.MyService interface over the URL mapped by /myService (bean name) in the simpliest case using BeanNameUrlHandlerMapping that does nothing else than map a URL to a bean with the URL value (this case /myService).
On the client side (consumer), you will have a bean configured just declaring the interface you expect the remote side is exposing. For our service would be something like:
<bean id="httpInvokerProxy" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceUrl" value="http://foo.bar.org/springSample/myService"/>
<property name="serviceInterface" value="foo.bar.MyService"/>
</bean>
At the moment spring instantiate the beans on client side, a proxy is instantiated and every method invocation would then be serialized and sent over HTTP to the endpoint (in this case http://foo.bar.org/springSample/myService. At the server side this request is deserialized and interpreted i.e. invoking the method on the real service being exposed (on our case DefaultMyService). The service will return something that will be serialized an gave as result to the HTTP request performed by the client. The client will receive it and deserialize it and return it to the original method invocator.
As you can see (and got from Spring documentation):
The server side will
Deserializes remote invocation objects and serializes remote
invocation result objects. Uses Java serialization just like RMI, but
provides the same ease of setup as Caucho's HTTP-based Hessian and
Burlap protocols.
The client side will
Serializes remote invocation objects and deserializes remote
invocation result objects. Uses Java serialization just like RMI, but
provides the same ease of setup as Caucho's HTTP-based Hessian and
Burlap protocols.
The serialization used with Spring Remoting on this case is Java serialization, meaning the HTTP request holds an entity body containing the serialized object (is good to keep in mind that in this case JVM version and class versions needs to be compatible).
The exposition is done as a whole, you could not separate it having one URL for each method of that interface. Therefore would be easier the use of Spring MVC and create a controller (#Controller) implement a method for each method you have on your interface annotating it as #RequestMapping (with the desired URL) and invoke the method on the service as follows the example:
Controller Sample
package foo.bar;
import foo.bar.service.MyService;
#Controller
public class MyService {
#Autowired
private MyService myService;
#RequestMapping("/sum/{num1}/{num2}")
public int sum(#PathVariable("num1") int num1, #PathVariable("num2") int num2) {
return myService.sum(num1, num2);
}
}
Using the context configuration
<context:component-scan base-package="foo.bar"/>
it would map the classes found on foo.bar and under packages automatically, meaning the Service implementation (DefaultMyService) could be mapped with #Service and #Autowired to the controller as done in the sample, without any bean configuration on the context xml.
But this will expose your service over REST interface, meaning it will handle HTTP plain requests that could be done by other consumers like a PHP consumer (this couldn't be done with Spring Remoting because it uses pure Java serialization).
If your client is Java you could definitively use Remoting and expose your service as a whole, if not the REST implementation using Spring MVC is a good solution.
Spring Documentation can be found here
I really recommend defining your controllers with the #Controller annotation. From the Spring documentation, start with adding a component scan to your Spring config.
<context:component-scan base-package="your.package.path"/>
Then, in a class, say, your.package.path.WhateverController, annotate the class:
#Controller
WhateverController
And annotate your methods with #RequestMapping:
#RequestMapping(value = "/helloWorld")
public ModelAndView helloWorld() {
...
}
#RequestMapping(value = "/project/{projectId}")
public ModelAndView helloWorld(#PathVariable String projectId) {
...
}
That's about it, multiple mappings per controller.
I think you need to tell us what you are trying to do first. If you are exposing your services to a universal web client, REST or SOAP would be a better option; if you are exposing your services to another Spring bean in another application, then Spring Remoting might suffice.
The comment "exposed web services" in your spring configuration file seems unclear of your purpose.
When you expose a service to remote clients, you always need to provide a contract to let the remote clients know what's possible. REST exposes that contract using URL's; SOAP exposes that contract using WSDL's; and Spring Remoting just directly gives the client that contract in a java interface, so the client can inject that interface into its own beans and use it like a locally defined bean.
In your question you mentioned mapping a method to an URL, Spring Remoting can't do that because it exposes intefaces; what you want to do sound very REST to me. And I agree with #stevebrown, exposing your services using a mapped controller is a good approach.
I have been tasked with updating a old project that I did not write.
The project is Spring MVC based and has an older Spring Controller configuration that I am unfamiliar with.
The controllers have bean configurations as follows
<bean id="controllerName" class="the.project.controller.class">
<property name"serviceName">
<ref bean="serviceName">
</property>
<property name"successView">
<value>viewName</value>
</property>
</bean>
where serviceName refers to a class annotated with #Service as follows
#Service(value=serviceName)
Is this the correct replacement for the xml configuration ?
#Autowired
#Qualifier("serviceName")
ServiceNameImpl serviceName
thanks
edit here is the organization of the serviceName class and interface
public interface ServiceName {
// methods omitted
}
#Service(value="serviceName")
public class ServiceNameImpl implments ServiceName {
//methods omitted
}
The #Resource annotation is not available to me ( Spring 3.0.7) and Autowire as above fails ( as it appears the type is not as expected as described below )
org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching beans of type [the.project.ServiceNameImpl] found for dependency
Given the edits, what am I doing wrong here ( Apologies for leaving out this information )?
in the end I need to be able to access the methods of the interface and its implementation
for example
serviceName.doSomething(someVar);
That's correct, but consider using private modifier for serviceName. Another way would be to use #Resource:
#Resource
private ServiceNameClass serviceName;
Note that in this case you don't need a #Qualifier("serviceName") - #Resource autowires by (field) name while #Autowired uses type by default. Only a problem when you have several beans of the same/compatible type.
Also you can skip the controllerName bean definition altogether by annotating controller class with #Controller.
BTW you can also shorten the XML configuration a bit by using the following syntax:
<bean id="controllerName" class="the.project.controller.class">
<property name"serviceName" ref="serviceName"/>
<property name"successView" value="viewName"/>
</bean>
(IntelliJ suggests this transformation and performs it for you).