I am writing Apache CXF web services and use Spring for loading my beans. My only bean is calling external process (MATLAB) from Java. My beans definition looks as below:
<bean id="matlabEngine" class="org.burch.pca.matlab.MatlabEngine"
init-method="start" scope="singleton">
<constructor-arg value="${matlab.engine.path}"></constructor-arg>
</bean>
<bean
class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="searchContextAttributes" value="true" />
<property name="contextOverride" value="true" />
<property name="ignoreResourceNotFound" value="true" />
<property name="locations">
<list>
<value>classpath:/pca-engine.properties</value>
</list>
</property>
</bean>
Piece of my MatlabEngine bean is as below:
/**
* Path to MATLAB engine.
*/
private String pathToEngine;
public MatlabEngine(String pathToEngine) throws MatlabConnectionException, MatlabInvocationException{
super();
setPathToEngine(pathToEngine);
}
/**
* Starts engine and goes to path defined by argument
* #param pathToEngine
* #throws MatlabConnectionException
* #throws MatlabInvocationException
*/
public void start() throws MatlabConnectionException, MatlabInvocationException{
//Create a factory
RemoteMatlabProxyFactory factory = new RemoteMatlabProxyFactory();
//Get a proxy, launching MATLAB in the process
proxy = factory.getProxy();
//Display welcoming messages in MATLAB Command Window
proxy.eval(MatlabCommandsRegistry.disp(MATLAB_ENGINE_WELCOME_1));
proxy.eval(MatlabCommandsRegistry.disp(MATLAB_ENGINE_WELCOME_2));
if(pathToEngine!= null && !"".equals(pathToEngine)){
logM("Switching to engine directory...");
String goToEngineRootDir = MatlabCommandsRegistry.cd(pathToEngine);
proxy.eval(goToEngineRootDir);
logM("Sucessfully changed engine dir to "+pathToEngine);
}
}
When I deploy web services in Tomcat, it brings up MATLAB process nicely (bean gets loaded).
However, when I create client request to web service endpoint with this code:
public static void main(String args[]) throws Exception {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.getInInterceptors().add(new LoggingInInterceptor());
factory.getOutInterceptors().add(new LoggingOutInterceptor());
factory.setServiceClass(UploadService.class);
factory.setAddress("http://localhost:8080/auth-ws-1.0.0/services/upload");
UploadService client = (UploadService) factory.create();
UploadEntity resume=new UploadEntity();
resume.setFileName("Image490");
resume.setFileType("jpg");
//Work arround data handler....
DataSource source = new FileDataSource(new File("C:\\Users\\Pictures\\thumb.png"));
DataHandler dataHandle = new DataHandler(source);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
dataHandle.writeTo(stream);
resume.setPayload(stream.toByteArray());
client.uploadFile(resume);
System.exit(0);
}
my server brings out new instance of MATLAB process (bean gets loaded again - very heavy and undesirable). What could I do to have only one bean which will be used to serve all processing and all requests? I am new to Spring, and I am thinking that my problem is that I am dealing with multiple contexts here. I want them to share a single instance of a singleton bean but don't know how to manage this.
Thank you for your time!
You should enable singleton mode for you bean.
Look at this: http://static.springsource.org/spring/docs/1.2.x/reference/beans.html#beans-factory-modes
Bean defenition may looks like this:
<!-- Spring property loading bean -->
<bean
class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer" singleton="true">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="searchContextAttributes" value="true" />
<property name="contextOverride" value="true" />
<property name="ignoreResourceNotFound" value="true" />
<property name="locations">
<list>
<value>classpath:/pca-engine.properties</value>
</list>
</property>
</bean>
I think you should manage MATLAB process lifecircle wisely to decrease resource loading.
Related
I am refering to Spring AOP by Mkyong http://www.mkyong.com/spring/spring-aop-example-pointcut-advisor/
It worked when tried running from main (i.e. App.java) as given on above link,
I want to integrate it in restful webservice where i have multiple service like CutomerService in mkyong's example.
For example i have controller which calls CustomerService,
#RestController
#RequestMapping(value = "/customer")
public class CustomerController{
#Autowired CustomerService customerService;
#RequestMapping(value = "/getCustomer", method = RequestMethod.GET")
public ResponseEntity<CommonResponse> getService(){
customerService.printName();
}
}
It didn't worked.
i have tried this also:
#Autowired
private ProxyFactoryBean customerServiceProxy;
#RequestMapping(value = "/getCustomer", method = RequestMethod.GET")
public ResponseEntity<CommonResponse> getService(){
CustomerService customerService = (CustomerService) customerServiceProxy
.getTargetSource().getTarget();
customerService.printName();
}
}
this dosent work either.
Any Solution for this?
my bean-config.xml is same as mkyong's example.
It worked ! Just need to change proxy class from "org.springframework.aop.framework.ProxyFactoryBean" to
"org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"
Auto proxy creator identifies beans to proxy via a list of names. So we don,t need to specify target bean instead list of beans can be specified and it will intercept automatically.
My config look as below:
<bean id="adviceAround" class="com.tdg.ess.semantic.event.log.AdviceAround" />
<!-- Event logging for Service -->
<bean id="testServicePointCut" class="org.springframework.aop.support.NameMatchMethodPointcut">
<property name="mappedNames">
<list>
<value>process</value>
</list>
</property>
</bean>
<bean id="testServiceAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut" ref="testServicePointCut" />
<property name="advice" ref="adviceAround" />
</bean>
<bean
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<!-- Differnt beans which have certain service defined like CustomerService-->
<value>testService1</value>
<value>testService2</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>testServiceAdvisor</value>
</list>
</property>
</bean>
Thanks everyone for looking into.
I am using JMX in Spring application with XML configuration:
<bean id="jmxExporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=bean1" value-ref="bean1"/>
<entry key="bean:name=bean2" value-ref="bean2"/>
<entry key="bean:name=bean3" value-ref="bean3"/>
</map>
</property>
<property name="notificationListenerMappings">
<map>
<entry key="*">
<bean class="com.test.listener"/>
</entry>
</map>
</property>
</bean>
<bean id="registry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean">
<property name="port" value="1099" />
</bean>
<bean id="serverConnector"
class="org.springframework.jmx.support.ConnectorServerFactoryBean">
<property name="objectName" value="connector:name=rmi" />
<property name="serviceUrl"
value="service:jmx:rmi://localhost/jndi/rmi://localhost:1099/jmxrmi" />
</bean>
I understand from various documents like instead of this XML configuration we could annotate it with #EnableMBeanExport and with #ManagedResource for the beans.
But i doubt how ConnectorServerFactoryBean gets configured with these annotations. Or is there any annotation available to configure RMI and connectorServerFactoryBean?
Also i need to know how to annotate, notificationListenerMappings configured?
P.S:
I have the code working for publisher and listener under XML configuration. I am planning to move it completely on annotation based as i do not want to disturb XML configuration already in PROD.
Edited
Found the following piece of code: planning to try it:
#Bean
public RmiRegistryFactoryBean registry() {
return new RmiRegistryFactoryBean();
}
#Bean
#DependsOn("registry")
public ConnectorServerFactoryBean connectorServer() throws MalformedObjectNameException {
ConnectorServerFactoryBean connectorServerFactoryBean = new ConnectorServerFactoryBean();
connectorServerFactoryBean.setObjectName("connector:name=rmi");
connectorServerFactoryBean.setServiceUrl("service:jmx:rmi://localhost/jndi/rmi://localhost:1099/connector");
return connectorServerFactoryBean;
}
Edit 2:
I am proceeding on above mentioned approach and I am able to configure MBeans and able to publish notifications. But unfortunately I am stuck up with configuring NotificationListener through Annotation.
I tried adding the following:
#Bean
#DependsOn("registry")
public ConnectorServerFactoryBean connectorServer() throws MalformedObjectNameException {
ConnectorServerFactoryBean connectorServerFactoryBean = new ConnectorServerFactoryBean();
connectorServerFactoryBean.setObjectName("connector:name=rmi");
connectorServerFactoryBean.setServiceUrl("service:jmx:rmi://localhost/jndi/rmi://localhost:1099/connector");
//TestListener is my NotificationListener class
ObjectName objectName = new ObjectName("bean:name=bean1");
connectorServerFactoryBean.getServer().addNotificationListener(objectName,
new TestListener(), null,null);
return connectorServerFactoryBean;
}
I am getting instanceNotFoundException stating bean:name=bean1 is not found. But I have configured like, #ManagedResource(objectName="bean:name=bean1") on my bean1.
Any help please on what i am missing?
#EnableMBeanExport has a server property, which reference the bean name of a server object.
see for example the test of this component, which use this server property : https://github.com/spring-projects/spring-framework/blob/master/spring-context/src/test/java/org/springframework/jmx/export/annotation/EnableMBeanExportConfigurationTests.java
I am using spring integration 4.2.4.RELEASE and I came across a bug. I am trying to create a inbound-channel using a custom directory based on "WatchServiceDirectoryScanner". When I try to inject this scanner I get the error.
"The 'filter' and 'locker' options must be present on the provided external 'scanner': ". No matter what combination of properties I tried it does not work. The reason is because even I supply a locker and filters to my custom scanner the "FileReadingMessageSource" in spring creates their own. Therefore when the it asserts
Assert.state(!(this.scannerExplicitlySet && (this.filter != null || this.locker != null)),
"The 'filter' and 'locker' options must be present on the provided external 'scanner': "
+ this.scanner);
it fails. There is a filter being "FileListFilterFactoryBean.initializeFileListFilter" no matter what combination has been set the code below will create one and the whole things just fails.
// no filters are provided
else if (Boolean.FALSE.equals(this.preventDuplicates)) {
filtersNeeded.add(new AcceptAllFileListFilter<File>());
}
else { // preventDuplicates is either TRUE or NULL
filtersNeeded.add(new AcceptOnceFileListFilter<File>());
}
I have read the post: How to skip the settings of filter and locker
but it does not work for me.
Has anybody find a solution for this?
Here is a sample XML configuration of creating the inbound channel.
<bean id="inboundChannel_3522_filter" class="org.springframework.integration.file.filters.CompositeFileListFilter">
<constructor-arg>
<list>
<bean class="org.springframework.integration.file.filters.RegexPatternFileListFilter">
<constructor-arg value="^Test_(20160216).TXT$" />
</bean>
</list>
</constructor-arg>
</bean>
<bean id="inboundChannel_3522_nio_locker" class="org.springframework.integration.file.locking.NioFileLocker" />
<bean id="inboundChannel_3522_scanner" class="com.test.spring.integraton.file.NonRecursiveWatchServiceDirectoryScanner"
>
<constructor-arg value="e:\data\incoming\Test-V2" />
<property name="filter" ref="inboundChannel_3522_filter"/>
<property name="locker" ref="inboundChannel_3522_nio_locker"/>
</bean>
<file:inbound-channel-adapter id="inboundChannel_3522" auto-create-directory="true" scanner="inboundChannel_3522_scanner"
directory="file:/c:/data/incoming/TEST/" prevent-duplicates="false" ignore-hidden="false" >
<integration:poller fixed-rate="1000"/>
</file:inbound-channel-adapter>
Basically I want to know if there is any way to override the bean FileReadingMessageSource so that I can change the Assert?
I have figure out how to get around this bug. So I create a scanner and I inject the filters and locker to the scanner. I create a custom FileReadingMessageSourceFactoryBean that skips creating filter and locker if a scanner has been injected. The CustomFileReadingMessageSourceFactoryBean with the changes is shown below. The changes occurs at line 172. The rest it is the same.
if (this.scanner != null)
{
this.source.setScanner(this.scanner);
}
else
{
if (this.filter != null)
{
if (this.locker == null)
{
this.source.setFilter(this.filter);
}
else
{
CompositeFileListFilter<File> compositeFileListFilter = new CompositeFileListFilter<File>();
compositeFileListFilter.addFilter(this.filter);
compositeFileListFilter.addFilter(this.locker);
this.source.setFilter(compositeFileListFilter);
this.source.setLocker(locker);
}
}
else if (this.locker != null)
{
CompositeFileListFilter<File> compositeFileListFilter = new CompositeFileListFilter<File>();
compositeFileListFilter.addFilter(new FileListFilterFactoryBean().getObject());
compositeFileListFilter.addFilter(this.locker);
this.source.setFilter(compositeFileListFilter);
this.source.setLocker(locker);
}
}
The new Spring XML looks as below. The difference is that we add the bean inboundChanel_3522.adapter.source at the end. What this does is when the inbound channel looks for a bean of type FileReadingMessageSourceFactoryBean it will append to its id the ".adpater.source" and if one exist it will use that otherwise it will create a default. In this case it will use our CustomFileReadingMessageSourceFactoryBean which has the logic to skip creating additional filters. It is very important that the custom bean comes after inbound-channel-adapter otherwise the bean factory will override it. Finally here is how the XML should look like.
<bean id="inboundChannel_3522_filter" class="org.springframework.integration.file.filters.CompositeFileListFilter">
<constructor-arg>
<list>
<bean class="org.springframework.integration.file.filters.RegexPatternFileListFilter">
<constructor-arg value="^Test_(20160216).TXT$" />
</bean>
</list>
</constructor-arg>
</bean>
<bean id="inboundChannel_3522_nio_locker" class="org.springframework.integration.file.locking.NioFileLocker" />
<bean id="inboundChannel_3522_scanner" class="com.test.spring.integraton.file.NonRecursiveWatchServiceDirectoryScanner">
<constructor-arg value="e:\data\incoming\Test-V2" />
<property name="filter" ref="inboundChannel_3522_filter"/>
<property name="locker" ref="inboundChannel_3522_nio_locker"/>
</bean>
<file:inbound-channel-adapter id="inboundChannel_3522" auto-create-directory="true"
scanner="inboundChannel_3522_scanner"
directory="file:/c:/data/incoming/TEST/" prevent-duplicates="false" ignore-hidden="false" >
<integration:poller fixed-rate="1000"/>
</file:inbound-channel-adapter>
<bean id="inboundChannel_3522.adapter.source" class="com.test.spring.integraton.file.CustomFileReadingMessageSourceFactoryBean">
<property name="scanner" ref="inboundChannel_3522_scanner"/>
<property name="directory" value="e:\data\incoming\Test-V2"/>
<property name="autoCreateDirectory" value="true"/>
</bean>
I am new to spring. Admins of my spring based web app want to configure settings from the web interface, so users can authenticate against LDAP server with their company username and password.
Change in LDAP settings should be possible without restarting the application. This might happen during a 'migration' or whatever reason. I have a couple beans, which need to be refreshed after the admin saves new settings for the LDAP server:
<bean id="ldapServer" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<constructor-arg>
<list>
<value>${ldap.url1}</value>
...
</list>
</constructor-arg>
<constructor-arg value="${ldap.basedn}"</constructor-arg>
<property name="referral" value="${ldap.referral}" />
<property name="baseEnvironmentProperties">...</property>
<property name="userDn" value="${ldap.username}" />
<property name="password" value="${ldap.password}" />
</bean>
I am using Springframework 3.1.2. The problem is, there are constructor arguments, which I want to change and not affect other running jobs. I tried playing with Scoped proxy, but not to much success yet:
<bean id="ldapServer" scope="prototype" ...>
<aop:scoped-proxy/>
I was successful though to get ldapServer to reinstantiate, when using prototype scope by running this piece of code:
#Controller
public class LDAPSettingsController implements ApplicationContextAware {
public ModelAndView handleRequest(...) {
DefaultSpringSecurityContextSource ldap;
ldap = context.getParentBeanFactor().getBean("ldapServer");
System.out.println(ldap.hashCode());
return new ModelAndView(new RedirectView('login.jsp'));
}
...
}
Are scopes and proxies here the way to go, or is the another mechanism in Spring to reflect configuration changes into a running program instance?
UPDATE: Clear up the question.
UPDATE: The root problem with the AOP proxies was following root exception:
java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
What worked was adding proxy-target-class="false" attribute to the <aop:scoped-proxy/> tag. I created a new scope, which works better than prototype - It destroys beans on settings update. Now I have this in my beans.xml:
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="ldap">
<ref bean="ldapScope" />
</entry>
</map>
</property>
</bean>
<bean id="ldapScope" class="com.myapp.SettingsScope" />
<bean id="ldapServer" scope="ldap" ...>
<aop:scoped-proxy proxy-target-class="false"/>
<constructor-args>
<list><value>${ldap.url1}</value> .. </list>
</constructor-args>
...
</bean>
I also have a controller for LDAP settings into which I inject ldapScope and I call a method which destroys current life-cycle objects and starts a new life-cycle every time, user presses the apply button.
PS: Not sure if I handle the life-cycle "re-start" in the right way - people my way to look for auto-start beans and start them after such event happens (i.e.: Setting -> Apply)
I currently have multiple Quartz pollers that check a multiple flags in the database and fire a service if flags are true and I also have one spring batch project reading files, then calling a service to update the information accordingly.
What i am wondering is if it is possible to get the spring batch application to only call a service very 5 minutes (dont check for any information just call a service which will handle all the business logic) so that i can remove the Quartz jobs from my application all my jobs are in one place (spring batch project)?
If so can any point me in the right direction on how to do this as i cannot find anything online to just set up a spring batch job just to fire a service?
You can simply schedule a Quartz job and call your service from executeInternal method of your schedular class. You will not be able to autowire your service directly in schedular class, so you need to set it using jobDataas Map.
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<bean id="cronTriggerCache"
class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="exampleJob" />
<property name="cronExpression" value="your cron expression" />
</bean>
</list>
</bean>
<bean name="exampleJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="example.ExampleJob"/>
<property name="jobDataAsMap">
<map>
<entry key="myService" ref="myService"/>
</map>
</property>
</bean>
package example;
public class ExampleJob extends QuartzJobBean {
private myService myService;
/**
* have getter setter for you service
*
*/
protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
// do the actual work
//call your service method here
}
}