How to configure Hessian on Spring MVC with xml config? - java

I am using Hessian in a Spring MVC project. I create server side implementation and then would like to configure the client. Client can be configured with code that uses HessianProxyFactory for the initialization of the client. The URL that is used is now hard coded in the code, but I would like to wire the service some how as a Spring bean so that the code side config would be handled with #Autowired annotation.
How to make this? All help is appreciated.

It is described in 20.3.3 Linking in the service on the client:
<bean id="accountService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
<property name="serviceUrl" value="http://remotehost:8080/remoting/AccountService"/>
<property name="serviceInterface" value="example.AccountService"/>
</bean>
Where example.AccountService is the service interface that the server implements. The client also needs that interface, but you probably know that.
Alternatively use Java configuration:
#Bean
public HessianProxyFactoryBean accountService() {
HessianProxyFactoryBean factory = new HessianProxyFactoryBean();
factory.setServiceUrl("http://remotehost:8080/remoting/AccountService");
factory.setServiceInterface(AccountService.class);
return factory;
}
Now you are capable of simply injecting:
#Autowired
private AccountService accountService;
The HessianProxyFactoryBean allows you to configure various other features like security and timeouts.

Related

Migrate from weblogic to tomcat

My application is currently working fine on weblogic. But due to upgrade the application, I want to use spring boot and embedded tomcat. I have a JndiTemplate bean such as:
<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">${java.naming.factory.initial}</prop>
<prop key="java.naming.provider.url">${java.naming.provider.url}</prop>
</props>
</property>
</bean>
This template is a helper to lookup for jndi objects like datasources and jms.
As you know the factory is weblogic.jndi.WLInitialContextFactory and url is t3://SERVER:PORT when we are on weblogic. but speaking of tomcat I dont know how to configure this template.
Tomcat is not a Java EE container like Weblogic. If you really want to keep using JNDI, have a look at TomEE.
Personally, I would let Spring manage the database connection. The advantage of using a framework like Spring is that it takes alot of responsibilities away from the container your application is running in, like eg. the database connection.
Spring Boot autoconfigures a DataSource by looking at:
your application.yml for the JDBC url and username/password
your pom.xml to see which database driver it will use (Spring Boot can also derive that from your JDBC url, but you'll have to add the driver library)
There's really nothing more to do.
You can now autowire the DataSource or use Spring's JdbcTemplate to avoid alot of boilerplate code.
This can be configured using Config files using #Bean annotation to initialize the TomcatEmbeddedServletContainerFactory . Please see below code snippet which might be helpful. Below is one of the format that needs to be updated as per your need.
#Bean
public TomcatEmbeddedServletContainerFactory tomcatFactory() {
return new TomcatEmbeddedServletContainerFactory() {
#Override
protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(Tomcat tomcat) {
tomcat.enableNaming();
return super.getTomcatEmbeddedServletContainer(tomcat);
}
/* (non-Javadoc)
* #see org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory#postProcessContext(org.apache.catalina.Context)
*/
#Override
protected void postProcessContext(Context context) {
ContextResource resource = new ContextResource();
resource.setName("your_app_DS_name");
resource.setType("your_app_property");
resource.setProperty("driverClassName", "your_app_Drive");
resource.setProperty("factory", "your_app_factory_property_details");
//similarly configure other needed and dependent properties.
context.getNamingResources().addResource(resource);
}
};
}

Spring #Resource Handling

I'm having trouble with a field annotated as #Resource in a Spring bean. What I have:
A field, with setter method, annotated #Resource
#Resource
private URL someUrl;
public void setSomeUrl(URL someUrl) {
this.someUrl = someUrl;
}
An <env-entry> tag in my deployment descriptor (web.xml)
<env-entry>
<env-entry-name>someUrl</env-entry-name>
<env-entry-type>java.net.URL</env-entry-type>
<env-entry-value>http://somedomain.net/some/path</env-entry-value>
</env-entry>
The application fails to start with a BeanCreationException, which I dont' expect because I don't necessarily want spring to inject a Spring-managed bean. I want Spring to process #Resource and retrieve the JNDI resource.
This is Spring 2.5.6SEC03 and the bean itself is annotated #Service for autowiring into other #Component instances. Servlet container in this case is Tomcat 7 but will ultimately be deployed onto Weblogic 10, so while I'd like ideally for a solution to work on both, Weblogic is the must-have.
Am I misusing this feature in Spring 2.5? In general? Is there some bit I'm missing? Something I misunderstand about JNDI? All help is appreciated. Thanks.
If you are using Spring Stereotype annotations, (#Service, #Component...), then you are probably including in your spring configuration the <context:component-scan /> element to pick them up. It is fine to do this, but it will automatically register a CommonAnnotationBeanPostProcessor with the application context, as stated just above the second note in this link.
The issue with including the CommonAnnotationBeanPostProcessor is that Spring handles the #Resource annotation and will attempt to inject beans from its application context. You can register your own CommonAnnotationBeanPostProcessor bean and tell Spring to allow direct JNDI access to these #Resource's by configuring the bean by setting the alwaysUseJndiLookup property to true.
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor">
<property name="alwaysUseJndiLookup" value="true"/>
</bean>
Pay attention to the note in the linked documentation:
NOTE: A default CommonAnnotationBeanPostProcessor will be registered by the "context:annotation-config" and "context:component-scan" XML tags. Remove or turn off the default annotation configuration there if you intend to specify a custom CommonAnnotationBeanPostProcessor bean definition!

Dynamic Remote Service Location - How to inject with Spring?

I'm currently working on a distributed services architecture for a project at work. Essentially, we are managing upwards of 200 machines. Each of these machines has an instance of a service running on them that allows us to interface with the machine in a specific way.
At the center I have a control application which needs to talk to these 200 identical services. I was hoping to use RMI via Spring Remoting to make this happen, allowing me to #Autowire my remote service into my #Controller and treat it like a local service with exception propagation and maybe in the future propagation of transactions / security context via hooks.
This works great for a single service on a single machine where I can hardcode the remote service in my Spring configuration, but what I'm not able to figure out is how to dynamically choose which service (aka, which machine) I want to talk to at runtime and make that remote service available the "Spring" way.
I would like to be able to configure this dynamically from a database table and use the same table information to do a service lookup, while still taking advantage of dependency injection.
I thought of maybe injecting some kind of service manager that could do a service lookup of some sort, but was hoping someone else has managed to solve this (or a similar) problem elegantly.
An example of a hardcoded, single service instance would be like so:
The first XML snippet is on the machine service itself, telling Spring to expose it via RMI
<!-- Expose DeviceService via RMI -->
<bean class="org.springframework.remoting.rmi.RmiServiceExporter">
<property name="serviceName" value="DeviceService" />
<property name="service" ref="deviceService" />
<property name="serviceInterface"
value="com.example.service.DeviceService" />
<property name="registryPort" value="1199" />
</bean>
The second XML snippet is on the client (control application) which lets me access the exposed service
<!-- Proxy our remote DeviceService via RMI -->
<bean id="remoteDeviceService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl" value="rmi://machineurl:1199/DeviceService"/>
<property name="serviceInterface" value="com.example.service.DeviceService"/>
</bean>
It's that second bit of configuration that I'm trying to make dynamic. As you can see, to create this service proxy, I need to know at bean creation time the service URL. The Service URL can be 1 of 200+ variations, depending on what machine I want to talk to. The service I'm talking to is the same interface, but I won't know which machine until runtime depending on the current request context.
You could create connections to your servers dynamically with an additional service and remove "remoteDeviceService" from your client/controll app, i.e.:
public class RMIConnectionService {
public DeviceService connect(String serverUrl) {
RmiProxyFactoryBean factory = new RmiProxyFactoryBean();
factory.setServiceInterface(DeviceService.class);
factory.setServiceUrl("rmi://" + serverUrl + ":1099/SERVICE_URL");
factory.afterPropertiesSet();
//...
return (DeviceService) factory.getObject();
}
}
Then add this service to you service layer:
<bean id="rmiService" class="...RMIConnectionService" >
//...
</bean>
In your logic autowire the service and use it like:
DeviceService server1 = rmiService.connect("127.0.0.1");
For Database config add your DAO to this service, to load the right url. Port and url, or even the interface class could be configured this way too.
I have no RMI service to test this, but it worked with Hessian too. I hope this helps you.

Advice on how to refactor spring mvc into plain servlets or jetty handler

I have a spring mvc app that I want to refactor out, speficially removing the spring related code and wiring.
It is a simple spring mvc at this point, so the key things I have to do our dependancy injection.
My application.xml has wirings for my Dao objects, injecting the datasource into my Dao objects.
How can I use a spring agnostic DI now? What do I have to change? I want to use guice unless you guys recommend otherwise
application.xml:
<bean id="userDao" class="com.blah.dao.UserDaoImpl">
<property name="dataSource" ref="dataSource" />
</bean>
What do you suggest I use to setup my datasource and connection pooling now?
The actual page/url mapping is specific to if I choose servlets or a jetty handler.
You can use the standard annotation #Inject for dependency injection. Both Spring and Guice support it.

Registering an MBean with the JBoss MBean server - Unable to find the JBoss MBean server

I am using Spring to expose an MBean and register it with the JBoss MBean server. This works fine when the war is dropped into an instance of JBoss. It does not work however when running unit tests (which makes sense since there is no instance of JBoss running)
Here is the extract from the spring configuration
<bean id="updateConfigMBean" class="mypackage.UpdateConfigMBean"/>
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="server">
<bean class="org.jboss.mx.util.MBeanServerLocator" factory-method="locateJBoss"/>
</property>
<property name="beans">
<map>
<entry key="mypackage:name=configurationMBean" value-ref="updateConfigMBean"/>
</map>
</property>
</bean>
What I am looking for is an elegant way of dealing with this issue(don't want to have two spring configurations (for testing and for deployment) and disabling the spring config validation test is not an option.
Thanks!
I am using #Bean to solve that problem. #Bean is tailor-made for doing environment-specific bean creation.
The logic below is basically, in development (Tomcat) and test (JUnit), use MBeanServerFactoryBean. Otherwise use the JBoss MBean Server.
#Bean
def mbeanServer: MBeanServer = {
val server = if (environment == "development" || environment == "test") {
val factory = new MBeanServerFactoryBean
factory.setLocateExistingServerIfPossible(true)
factory.setRegisterWithFactory(true)
factory.afterPropertiesSet()
log.info("using default MBeanServer")
factory.getObject
} else {
val clazz = Class.forName("org.jboss.mx.util.MBeanServerLocator")
val locateJboss = clazz.getMethod("locateJBoss", List.empty[Class[_]].toArray: _*)
log.info("using JBoss MBeanServer")
locateJboss.invoke(null,
List.empty[java.lang.Object].toArray: _*).asInstanceOf[MBeanServer]
}
log.info("mbeanServer: " + server)
server
}
In Spring 3.1 you are able to solve this problem and still use XML configuration by using profiles. But the above works with Spring 3.0.
This is one of those situations where you are probably going to have to have two configs, one for testing and one for deployment.
This is where Maven is good, as you have a clear separation between your deployment configs and your test configs. If you are worried about keeping two configs up todate, then you need to structure your configs in such a way that all the common bits are imported into the other configs (that is how we did it).

Categories

Resources