Reputation: 20976
I need to execute task on remote machine.
This task is dummy Runnable or Callable and Serializable to be transferred to remote host, deserialized and executed there.
I need to use spring beans from that task to execute it on remote machine.
What could be the elegant way to 'serialize' bean name when task is serialized on client machine and 'deserialize' real bean while deserialization on remote machine?
Any other solutions?
Upvotes: 0
Views: 1461
Reputation: 20976
private static class MyCommand implements Callable<String>, Serializable {
private static final long serialVersionUID = 8980820796677215627L;
private transient SpringBean springBean;
private String bar;
public InitDoneRemoteCommand(SpringBean springBean, String bar) {
this.springBean = springBean;
this.bar = bar;
}
@Override
public String call() {
return springBean.foo(bar);
}
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
out.writeObject(getBeanName(springBean));
}
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
springBean = getBean((String) in.readObject());
}
}
SpringContext .java
@Resource
public class SpringContext implements ApplicationContextAware, BeanPostProcessor, BundleContextAware, ServiceListener {
private static ApplicationContext applicationContext;
private static BundleContext bundleContext;
private static Map<Object, String> springBeanToName = synchronizedMap(new WeakHashMap<Object, String>());
private static Map<String, ServiceReference> osgiNameToServiceReference = synchronizedMap(new WeakHashMap<String, ServiceReference>());
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static BundleContext getBundleContext() {
return bundleContext;
}
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
ServiceReference ref = osgiNameToServiceReference.get(name);
if (ref != null)
return (T) bundleContext.getService(ref);
return (T) applicationContext.getBean(name);
}
public static String getBeanName(Object bean) {
if (isOsgiBean(bean))
return getOsgiBeanName(bean);
return springBeanToName.get(bean);
}
public static boolean isOsgiBean(Object bean) {
return bean instanceof ImportedOsgiServiceProxy || bean instanceof ServiceReferenceProxy || bean instanceof ServiceReference;
}
public static String getOsgiBeanName(Object proxy) {
if (proxy == null)
return null;
ServiceReference serviceReference = null;
if (proxy instanceof ImportedOsgiServiceProxy)
serviceReference = ((ImportedOsgiServiceProxy) proxy).getServiceReference().getTargetServiceReference();
else if (proxy instanceof ServiceReferenceProxy)
serviceReference = ((ServiceReferenceProxy) proxy).getTargetServiceReference();
else if (proxy instanceof ServiceReference)
serviceReference = ((ServiceReference) proxy);
if (serviceReference != null)
return (String) serviceReference.getProperty(OSGI_BEAN_NAME_PROPERTY);
throw new IllegalArgumentException(proxy.toString());
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
springBeanToName.put(bean, beanName);
return bean;
}
@Override
public void serviceChanged(ServiceEvent event) {
ServiceReference ref = event.getServiceReference();
String name = getOsgiBeanName(ref);
if (event.getType() == ServiceEvent.REGISTERED)
osgiNameToServiceReference.put(name, ref);
else if (event.getType() == ServiceEvent.UNREGISTERING)
osgiNameToServiceReference.remove(name);
}
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
SpringContext.applicationContext = context;
}
@Override
public void setBundleContext(BundleContext bundleContext) {
SpringContext.bundleContext = bundleContext;
bundleContext.addServiceListener(this);
}
}
Upvotes: 1
Reputation: 3300
If you have access to the ApplicationContext you can ask it to create the instance for you, which will e.g. enable autowiring:
appContext.getAutowireCapableBeanFactory().createBean(
beanClass,
AbstractBeanDefinition.AUTOWIRE_BY_TYPE,
true)
A more elegant way would be to annotate the class with @Configurable, described here.
Upvotes: 0