Niolocker is not working in spring boot application - java

Trying to test file lock mechanism in spring boot application by starting two instances of same application pointing to same source path which contains 10 files. Expecting only one instance should process a file and once processed it will be deleted from source. Same file should not be processed by other instance.So added Niolocker to the scanner. Tested in both windows and linux environments.But in windows, facing below exception in both the instances... In Linux, same file is polled/processed by both instances. No impact in Linux. Have implemented the below logic to acquire lock.
Please suggest on this.
Windows exception:
java.io.IOException: The process cannot access the file because another process has locked a portion of the file
Linux:
Both instance poller picks the same file and processing it
<file:inbound-channel-adapter id="filesInChannel" directory="file:${base.path}" auto-startup="false" scanner="recursiveScanner" auto-create-directory="true">
<integration:poller id="poller" max-messages-per-poll="${max.messages.per.poll}" fixed-rate="${message.read.frequency}" task-executor="pollingExecutor">
<integration:transactional transaction-manager="transactionManager" />
</integration:poller>
</file:inbound-channel-adapter>
<bean id="inboundFilter" class="org.springframework.integration.file.filters.CompositeFileListFilter">
<constructor-arg>
<list>
<bean class="org.springframework.integration.file.filters.AcceptOnceFileListFilter"/>
<bean class="org.springframework.integration.file.filters.RegexPatternFileListFilter">
<constructor-arg value="${file.type}"/>
</bean>
</list>
</constructor-arg>
</bean>
<bean id="inboundChannelNioLocker" class="org.springframework.integration.file.locking.NioFileLocker" />
<bean id="recursiveScanner" class="org.springframework.integration.file.RecursiveDirectoryScanner">
<property name="filter" ref="inboundFilter" />
<property name="locker" ref="inboundChannelNioLocker"/>
</bean>

The NioLocker is really operation system dependent and doesn't guarantee exclusive access to the file. Well, only Windows does that for us properly.
I even start considering to deprecate and remove it altogether from the Framework. It causes too much confuses for target users...
Instead of file locker you need to consider to use a FileSystemPersistentAcceptOnceFileListFilter based on the shared ConcurrentMetadataStore. So, this way really only one instance will pick up the file for processing. All others will skip it and move on to the next files.
See Reference Manual for more info.

Related

How to integrate my Java application as a consumer?

I have a Java application. How do I use it as consumer of messages in activemq? Do I need to write any code where I will be passing my name of java application to list it as a consumer?
Or do I need to integrate any software (like camel, spring) which will help me to achieve this. Right now what I am looking for is that this Java application needs to be called when activemq gets populated with a message.
If I need to integrate something into my activemq please put some links which will clearly explain how to go about the integration.
PS I am new to activemq and I am super dependent on your help .
If you are working on a Spring application. Or have knowledge of how to work with it, it's pretty simple.
The configuration would be something like this:
<bean id="messageListener" class="jmsexample.ExampleListener" />
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="destination"/>
<property name="messageListener" ref="messageListener" />
</bean>
Look at the documentation: http://static.springsource.org/spring/docs/3.0.x/reference/jms.html

Multiple resource providers in same transaction Spring

I am using Jackrabbit to store files (data store) and Hibernate almost everything else. I do not know alot of transactions etc. but I know that I want a global transaction for these two so that an exception rolls back everything. At the moment the database stuff is rolled back, but Jackrabbit isn't.
I am using Spring 3.2. I have deployed the Jackrabbit JCA adapter to JBoss (7.1.1). I have these lines in the config xml:
<bean id="txManager"
class="org.springframework.transaction.jta.JtaTransactionManager"></bean>
<tx:annotation-driven transaction-manager="txManager"
proxy-target-class="true"/>
However that isn't enough it seems. Could somebody give me some clues to what I need to read about/where to find information on this? I need to roll back everything if something happens to one of the resource providers.
This was quite tricky to set up. One gotcha was the spring automagically uses 'transactionManager' as a default name which caused problems. It is definitely worth the effort though as synchronising mismatched data sources would soon become a nightmare.
Here is my sample config that worked for me. Of course now we would probably use #Configuration instead of the xml. This worked using, Spring Data, JTA, MySQL with XA driver and Neo4j. Neo4j specific things have been omitted.
Spring Data may also help you here.
Here is a starter...
<tx:annotation-driven transaction-manager="xaTransactionManager" />
<bean id="xaTransactionManager" class="some.type.of.ChainedTransactionManager">
<constructor-arg>
<list>
<ref bean="jpaTransactionManager"/>
<ref bean="otherTransactionManager"/>
</list>
</constructor-arg>
</bean>
<bean id="jpaTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="localContainerEntityManagerFactoryBean"/>
</bean>
<bean id="otherTransactionManager" class="other.type.of.jta.TransactionManager">
<property name="transactionManager" ref="otherTransactionManagerService"/>
</bean>

Passing Env. into my application-config.xml

I'm currently working on a java application. The application has 3 different properties files. I want to be able to set the name of the properties file based on the name of the server the app is running on.
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:/config/InfSit.properties</value>
</list>
</property>
</bean>
This is from my application-config.xml and currently works fine. I want to be able to change the name of the properties file based on the server the application is running on. So "InfSit.properties" would be "Inf${Env}.properties" (or something along these lines) - But I need a way to pass in the ${Env} parameter (could even be a string from another class). Can anyone suggest the best way to do this?
Thanks.
Set system property in java args
java -Denv=Sit ...
and it will replace ${env} in location expr
<context:property-placeholder location="classpath:/config/Inf${env}.properties" />
Just set the variable and reference it, I do similar with CATALINA_HOME :
<context:property-placeholder location="file:${catalina.home}/conf/database_UAT.properties"
ignore-unresolvable="true"/>
Just make sure you set the variable correctly ...

How to change the TaskExecutor implementation dynamically depending on the application server

I am using Spring 3.0.x to get a WorkManager from an application server and use it to run scheduled jobs that need database access. The problem is, is that this application could be deployed to different Java application servers - in this case, to Websphere 7.0 and GlassFish 3.1 OSE. (Crazy combo, I know...)
The problem I am having is that before deploying to either, I have to change the bean to reference the appropriate TaskExecutor class used for each server. I have Spring load up an applicationContext.xml with these beans in it.
For Websphere, I have to pull the WorkManager externally and use the following bean:
<bean id="myTaskExecutor" class="org.springframework.scheduling.commonj.WorkManagerTaskExecutor">
<property name="workManagerName" value="wm/default" />
<property name="resourceRef" value="true"/>
</bean>
and the web.xml has something like this:
<resource-ref>
<description>WorkManager</description>
<res-ref-name>wm/default</res-ref-name>
<res-type>commonj.work.WorkManager</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
For GlassFish, I can just use the bean:
<bean id="myTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
</bean>
Can I somehow dynamically change which TaskExecutor implementation is used on the fly?
I could easily check for the Websphere resource to determine if I am on Websphere, then fall back to GlassFish. But how to load a class like that with Spring (using Annotations or otherwise) is baffling me.
Any help is appreciated. Thanks!
P.S. I am not worried about being J2EE compliant for GlassFish - it's just that Websphere forces you to be so (hence pulling an external WorkManager)
You can easily use a custom VM argument to determine what environment you are running in, and use that to load the appropriate context file.
One file for each supported environment, all of which define the same bean.
task-exec-was.xml
task-exec-glassfish.xml
Add a required VM argument.
-Dapp.server=was
Then, wherever you actually load the bean you include the appropriate file based on a PropertyPlaceholderConfigurer.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" />
<import resource="task-exec-${app.server}.xml" />
Edits based on information in the comments.
You can override for the environment you do have control over in this case.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
<property name="location" value="classpath:spring/was.properties/>
</bean>
<import resource="task-exec-${app.server}.xml" />
Now you have a file called spring/was.properties that defines a property app.server=was, which is read by default. In Glassfish, you supply the same property as a VM argument, which will now override the property read from the file.

how do I change persistence.xml at run time

I am new to openJPA.
I have a scenario where, depending upon the server where my application is running, I need to change the settings to persistance.xml.
For eg. if its running on Server A, then it should use different database(different url), different password etc. and if the application is running on Server B then it should use different information.
And could you also tell me, which way should it be done, using datasource or simply putting properties under persistence-unit.
FYI I am using WS app. server 7 and RAD 7.5
Any type of help would be highly appreciated.
You're using an application server so you don't need to set database connection settings in the persistence.xml file. You should be able to create a JNDI data source in your appserver and then use that. EAch server could have the data source have the same JNDI name and then there'll be no need for any persistence.xml differences.
Workshop, JPA, and DataSources seems particularly relevant to you. As does Setting up a JNDI data source in WebSphere 6.0/6.1 and WebSphere + JNDI + Spring Framework + Hibernate.
Are you using Spring? If so, then the problem is easy to solve: you don't put the data source information in your persistence.xml, you put it in your application context and that'll have different configuration on each server.
For example:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:database.properties"/>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${database.class}"/>
<property name="url" value="${database.url}"/>
<property name="username" value="${database.username}"/>
<property name="password" value="${database.password}"/>
</bean>
and each server could have a different database.properties file on each server (where each is in the classpath somewhere in this example):
database.username=scratch
database.password=scratch
database.class=oracle.jdbc.OracleDriver
database.url=jdbc:oracle:thin:#localhost:1521:XE
Changing persistence.xml at runtime is going to be problematic as that's not really how JPA is designed.
Of course, you can use JNDI data sources with Spring also.

Categories

Resources