FileReadingMessageSource.WatchServiceDirectoryScanner: turn off recursive descent into sub-directories? - spring

Versions:
Spring: 5.2.16.RELEASE
Spring Integrations: 5.3.9.RELEASE
macOS Big Sur: 11.6
I am using XML to set up the directory scanner FileReadingMessageSource.WatchServiceDirectoryScanner like so:
<int-file:inbound-channel-adapter id="channelIn" directory="${channel.dir}" auto-create-directory="false" use-watch-service="true" filter="channelFilter" watch-events="CREATE,MODIFY">
<int-file:nio-locker ref="channelLocker"/>
<int:poller fixed-delay="${channel.polling.delay}" max-messages-per-poll="${channel.polling.maxmsgs}"></int:poller>
</int-file:inbound-channel-adapter>
with the following bean definitions:
<bean id="channelLocker" class="org.springframework.integration.file.locking.NioFileLocker"/>
<bean id="channelFilter" class="org.springframework.integration.file.filters.ChainFileListFilter">
<constructor-arg>
<list>
<bean class="org.springframework.integration.file.filters.SimplePatternFileListFilter">
<constructor-arg value="SpreadSheets*.xls" />
</bean>
<bean id="filter" class="org.springframework.integration.file.filters.LastModifiedFileListFilter">
<property name="age" value="${channel.filter.age}" />
</bean>
<ref bean="persistentFilter" />
</list>
</constructor-arg>
</bean>
<bean id="persistentFilter" class="org.springframework.integration.file.filters.FileSystemPersistentAcceptOnceFileListFilter">
<constructor-arg index="0" ref="metadataStore" />
<constructor-arg index="1" name="prefix" value="" />
<property name="flushOnUpdate" value="false" />
</bean>
If I look at logs for org.springframework.integration.file.FileReadingMessageSource, I notice that we register both the specified directory (ie, ${channel.dir}) as well as any of its sub-directories. That is, I see logs like this:
15:44:45.706 [main] DEBUG org.springframework.integration.file.FileReadingMessageSource - registering: /Users/kc/scan.here for file events
15:44:45.711 [main] DEBUG org.springframework.integration.file.FileReadingMessageSource - registering: /Users/kc/scan.here/and.here for file events
I've looked Spring docs as well as API docs for the relevant software modules (Eg, FileReadingMessageSource), but I don't see any property or configuration option for turning off recursive descent into sub-directories.
What is the recommended practice here for scanning only files within the specified directory, but not recursing any deeper than that?

If you don't a recursion and scan the whole file tree, just don't use that watch service!
For the create and modify events you can configure a FileSystemPersistentAcceptOnceFileListFilter which checks for the file.lastModified(). I see you do that anyway, therefore it is not clear why do you need a watch service at all?
See some related discussed here: https://github.com/spring-projects/spring-integration/issues/3557.
If you still have some reasonable argument to use watch service for only a root dir, please add a comment into that issue and we will revise it respectively.

Related

How do I automatically reload my properties in my Spring XML appilcation context?

I’m using Spring 3.2.11.RELEASE. I currently have the following set up in my application context file for the purposes of loading a cron trigger based off a schedule defined in a properties file (the property = cron.schedule) …
<bean id="localPropertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:application.properties</value>
</property>
</bean>
…
<bean id="updateResourcesJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="myService" />
<property name="targetMethod" value="myMethod" />
<property name="concurrent" value="true" />
</bean>
<bean id="updateResourcesCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="myJob" />
<property name="cronExpression" value="${cron.schedule}" />
</bean>
My question is, I would like to create an XML configuration in my context file that allows me to edit my properties file and have everything automatically reloaded without having to restart my server or re-deploy my application. I have read several places about Apache Commons Configuration, but I can’t figure out how to take the above and rewrite an XML config that would utilize the configuration.
Thanks for any help, - Dave

Update Views With Spring MVC And Thymeleaf Without Redeploy The App

I am using Spring MVC 3.2, Thymeleaf, Thymeleaf dialect with Tomcat and every time that I change a view I don't want redeploy my app. As suggested from others I am setting:
<property name="cacheable" value="false"/>
in the template resolver, but it not working.
Also a full reload (CTRL + F5) has not effect.
Here my full Thymeleaf configuration:
<!-- Thymeleaf template engine -->
<bean id="templateResolver"
class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
<property name="prefix" value="/WEB-INF/templates/" />
<property name="suffix" value=".html" />
<property name="templateMode" value="HTML5" />
<property name="cacheable" value="false"/>
</bean>
<bean id="templateEngine"
class="org.thymeleaf.spring3.SpringTemplateEngine">
<property name="templateResolver" ref="templateResolver" />
<!-- These lines add the dialect to Thymeleaf -->
<property name="additionalDialects">
<set>
<bean class="nz.net.ultraq.thymeleaf.LayoutDialect"/>
</set>
</property>
</bean>
<bean class="org.thymeleaf.spring3.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine" />
</bean>
Is there something else that I can do to resolve this issue?
It depends on many many things and mainly on "where and how" you update your view. If you are using a IDE (Netbeans or Eclipse) it main depend on the IDE itself and on the deployement process.
Current organization on disk :
Source directories => [ on build ] => target or build directories => [ on deploy ] => tomcat directories
But IDE often tries to be developper's friendly and it can happen that target directories and tomcat directories are the same. But it also may depend of the IDE and its configuration.
Also when you save files under source webapp, the IDE may automatically copy them to target.
But this is not guaranteed by <property name="cacheable" value="false"/> of Thymeleaf config. All what it guarantees is that if a template is changed in tomcat directories, next request will use it.
So to be sure where the problem really comes, you will have to find where tomcat actually gets the templates and if those templates are modified.
(and I didn't even talked of browsers cache ...)
In Tomcat "Server Options", check "Serve modules without publishing" did the trick for me.

Change the path of MirrorWriterProcessor in Heritrix 3.1.0

I am crawling using Heritrix 3.1.0. I am trying to save the files using the MirrorWriterProcessor. However, this option is not available in the crawler-beans.cxml.
What I did was to replace the "warcWriter" "org.archive.modules.writer.WARCWriterProcessor"
to
"org.archive.modules.writer.MirrorWriterProcessor"
However, this processor write the mirror content to
$HERITRIX_HOME/mirror
I configured the "path" to "${launchId}/mirror", hoping Heritrix to write the mirror directory to under the job directory.
What shall I do to change the path of MirrorWriterProcessor to under the job directory?
You cannot, at the moment, use tags like the ones warcWritter accepts. You can, however, write some spring magic to create your own stamped folders. This creates a factory for the format function of SimpleDateFormat and spits out a string you can use to create a stamped folder.
<bean id="dateFormat" class="java.text.SimpleDateFormat">
<constructor-arg value="ddMMyyyy" />
</bean>
<bean id="formatedDate" factory-bean="dateFormat" factory-method="format">
<constructor-arg>
<bean class="java.util.Date" />
</constructor-arg>
</bean>
<bean id="mirrorWriter" class="org.archive.modules.writer.MirrorWriterProcessor">
<property name="path">
<bean class="java.lang.String">
<constructor-arg value="#{formatedDate + '/mirror'}" />
</bean>
</property>
...

deployment for different environments with maven and spring

I've got two properties files:
environment.properties:
- project.host.db3.database.name=oracle
application.properties:
- database.name=${project.host.db3.database.name}
The first one represents the environment variables and the second one the properties to be used in a spring project, in this configuration i try to set the environment.properties but of course it doesn't work:
<bean id="systemPropertiesLoader"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" value="#{#systemProperties}" />
<property name="targetMethod" value="putAll" />
<property name="arguments">
<util:properties location="classpath:environment.properties" />
</property>
</bean>
<bean id="propertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
depends-on="systemPropertiesLoader">
<property name="locations">
<list>
<value>classpath:application.properties</value>
</list>
</property>
<!-- bean using database.name -->
Is it doable?, and if not, how do people have agnostic properties in their projects (like database.name), and only one file (war, jar, etc.) to be deployed?
Well, it seems it's doable for beans xml defined as long as you define your properties it like this:
<bean id="propertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
depends-on="systemPropertiesLoader">
But if you ever try to access the properties from a servlet:
this.getClass().getClassLoader().getResourceAsStream("application.properties");
chances are you get this:
bad port configuration: ${project.host.db3.database.port}
java.lang.NumberFormatException: For input string: "${project.host.db3.database.port}"
In answer to yorkw, now i can have the same war to be deployed in several environments and configure the host with -Denvironment=development, so i can deploy a properties file for development, production, etc. and simply use:
<bean id="systemPropertiesLoader"
class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" value="#{#systemProperties}" />
<property name="targetMethod" value="putAll" />
<property name="arguments">
<util:properties location="classpath:**${environment}/**environment.properties" />
</property>
</bean>
Otherwise i should have the application.properties substituted before deployment for every environment. I'm sure there are better solutions than this.

<jee:jndi-lookup default-value and the use of classpath

I am really stuck on this one... Help! :)
I am using j2ee:jndi lookup for a property file. The following works fine:
<bean class="org.springframework.core.io.FileSystemResource">
<constructor-arg>
<jee:jndi-lookup id="myProps" jndi-name="myProps" resource-ref="true" />
</constructor-arg>
</bean>
However, I want to handle the case where the jndi lookup fails but will fall back on a default file located in WEB-INF/classes folder. If I use the default-value as below, the webapp throws an exception complaining that it cannot find the file "classpath:myprops.properties"
<bean class="org.springframework.core.io.FileSystemResource">
<constructor-arg>
<jee:jndi-lookup id="myProps" jndi-name="myProps" resource-ref="true"
default-value="classpath:myprops.properties" />
</constructor-arg>
</bean>
However, if I hard-code a specific path for default-value, then it works fine, but that is unacceptable as a final solution.
Thus, my issue is how to use "classpath:" so that it gets properly resolved?
This is the overall usage I'm employing:
<bean id="authServerProperties"
class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="ignoreResourceNotFound" value="true"/>
<property name="location">
<bean class="org.springframework.core.io.FileSystemResource">
<constructor-arg>
<jee:jndi-lookup id="myProps" jndi-name="myProps" resource-ref="true"
default-value="classpath:myprops.properties" />
</constructor-arg>
</bean>
</property>
.....
</bean>
Let Spring use its built-in PropertyEditor support to decide on the type of resource, rather than supplying an explicit FileSystemResource bean as this won't work with classpath resources (it needs to be configured with a path on the file system). Instead you should use something like
<bean id="authServerProperties"
class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="ignoreResourceNotFound" value="true"/>
<property name="location" ref="myProps" />
</bean>
<jee:jndi-lookup id="myProps" jndi-name="myProps" resource-ref="true"
default-value="classpath:myprops.properties"/>
Here we are setting the location to be a string value and allowing Spring to convert that to the appropriate resource type, so if you have
<env-entry>
<env-entry-name>myProps</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>file:///Users/something/myProps.properties</env-entry-value>
</env-entry>
in your web.xml, it will use a UrlResource with the given file URL, otherwise it will create a ClasspathResource to look for the file myprops.properties.

Resources