I'm trying to get a list of filenames from a remote directory and all its subdirectories using Spring Integration 4.1.5. Since I can only use SFTP to connect to the remote server, I need to use an int-sftp:outbound-gateway. Seems like it would be pretty straightforward:
<int-sftp:outbound-gateway id="remoteSftpLS"
session-factory="sftpSessionFactory"
request-channel="triggerChannel"
command="ls"
command-options="-1 -R"
remote-file-separator="/"
expression="payload"
charset="UTF-8"
filter="fileFilter"
reply-channel="lsResultChannel" />
However, it seems like anything I put into command-options is ignored:
Regardless of whether I use -R or not, I only get entries from the
top-level directory.
Regardless of whether I use -1 or not, I only get FileInfo objects, not filename strings.
What am I missing here?
Does not make sense. Just have tested it locally. The result is like:
payload = {ArrayList#3873} size = 3
0 = "sftpSource1.txt"
1 = "sftpSource2.txt"
2 = "subSftpSource/subSftpSource1.txt"
SftpServerOutboundTests.testInt3172LocalDirectoryExpressionMGETRecursive with the sftpSource as a remote directory and:
<int-sftp:outbound-gateway session-factory="sftpSessionFactory"
request-channel="inboundMGetRecursive"
command="ls"
expression="payload"
command-options="-1 -R"
reply-channel="output"/>
as a config.
Maybe your filter is guilty ?
protected final List<F> filterFiles(F[] files) {
return (this.filter != null) ? this.filter.filterFiles(files) : Arrays.asList(files);
}
Related
I would like to define an
<int-jdbc:outbound-gateway/> with query and without update to retrieve data from database. Then I would like to use the int-jdbc:outbound-gateway as an implementation of Service.findSomeData() interface method. The data retrieved from interface implementation is used in my custom transformer's CheckService class. See the configuration below:
<int:service-activator method=“performCheck”>
<bean class=“com.example.service.CheckService”
c:service-ref=“service”
</int:service-activator>
<int:gateway id=“service” service-interface=“com.example.service.Service”>
<int:method name=“findSomeData” request-channel=“jdbcChan” reply-channel=“jdbcChanReply”/>
</int:gateway>
<int-jdbc:outbound-gateway request-channel=“jdbcChan”
data-source=“pooledDs” row-mapper=“dataRowMapper” reply-channel=“jdbcChanReply”>
<int-jdbc:query>
select some, data from some_table
</int-jdbc:query>
The problem is that I get ReplyRequiredException exception when I move my payload to jdbcChan:
org.springframework.integration.handler.ReplyRequiredException: No reply produced by handler 'org.springframework.integration.jdbc.JdbcOutboundGateway#0', and its 'requiresReply' property is set to true.
I decided to pay more attention on example located in spring in spring-integration-samples repository on GitHub, but looks like it also does not work as expected. I get exactly the same exception in example project trying to find User by name foo. You can easily reproduce the exception with basic jdbc example located on GitHub and the following test method:
#Test
public void findPerson() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"/META-INF/spring/integration/spring-integration-context.xml");
PersonService service = context.getBean(PersonService.class);
final List<Person> foo = service.findPersonByName("foo");
assertThat(foo, is(not(empty())));
}
Am I doing it wrong or there is a bug in latest Spring Integration JDBC? (for me looks like even example is broken)
I fixed the sample.
We changed the default for requires-reply to true a long time ago but the sample was never updated.
assertThat(foo, is(not(empty())));
However, the List<Person> is null when no results are received.
EDIT
But I would expect empty list instead of a null if ResultSet was empty.
That's not how it works.
If the resultSet is empty, null is returned (hence the original error you were seeing).
If the resultSet has 1 entry, just that entry is returned.
Otherwise a list of entities is returned.
Object payload = list;
if (list.isEmpty()) {
return null;
}
if (list.size() == 1) {
payload = list.get(0);
}
return payload;
It's been like that forever but I believe the single Object Vs. List is wrong (if maxRows > 1).
maxRows is 1 by default so it made sense then; however, if maxRows is > 1 and only 1 row is returned I think it should still be a list of 1. The application shouldn't have to check the type of the result. It either expects a list or a single object (or null). INT-4559.
I want get message in queue (in) and I want correlate messages.
I must to put value from property in jms selector in Groovy but this not works.
The message is not picked up from the queue.
<script:transformer name="some">
<script:script engine="groovy">
<property key="id" value="123" />
<script:text>
String url = "jms://queue.in?selector=someId%3Did";
return muleContext.client.request(url, 0);
</script:text>
</script:script>
</script:transformer>
Some intresting is that works this:
jms://queue.in?selector=MULE_CORRELATION_ID%3Did
but I don't want above.
I want use another property name.
Not works this:
jms://queue.in?selector=someId%3Did
and this:
jms://queue.in?selector=someId%3D+id
and this:
jms://queue.in?selector=someId%3D+"id"
and this:
jms://queue.in?selector=someId%3Did
but works this (some interesting):
jms://queue.in?selector=someId%3D'123456'
but i don't want above.
What am i doing wrong ?
Hurra! I did it :)
It works this:
jms://queue.in?selector=someId%3Did+'$id'
I'm new with Spring and I'm using Citrus Framework.
I'll try to change, dynamically, the inbound-channel-adapter destination variable. This variable is located in properties file and change all the time.
Currently I'm using an AtomicReference and I change its value in java code
In context.xml :
<bean id="targetDir" class="java.util.concurrent.atomic.AtomicReference">
<constructor-arg value="${output.path.temp}"/>
</bean>
<file:inbound-channel-adapter id="fileInboundAdapter" auto-create-directory="false"
channel="fileChannel" directory="file:#targetDir.get()" auto-startup="false"
filename-pattern="*.xml">
<si:poller cron="0 * * * * ?"/>
</file:inbound-channel-adapter>
And in java file :
SourcePollingChannelAdapter fileInboundAdapter = (SourcePollingChannelAdapter)context.getApplicationContext().getBean("fileInboundAdapter");
if (fileInboundAdapter.isRunning()) {
fileInboundAdapter.stop();
#SuppressWarnings("unchecked")
AtomicReference<String> targetDir = (AtomicReference<String>)
context.getApplicationContext().getBean("targetDir", AtomicReference.class);
targetDir.set(strOutPath[0]+"/"+strOutPath[1]+"/"+strOutPath[2]+"/"+strOutPath[3]+"/");
fileInboundAdapter.start();
}
This solution don't works ... someone have any solutions ?
Thanks a lot.
That's true. Because your AtomicReference doesn't have affect to the target directory.
You do this directory="file:#targetDir.get()". It isn't correct at all, because this String will try to be converted to the File object. If you want to use here a SpEL it should be like this:
directory="#{targetDir.get()}"
without any file: prefix.
Anyway it doesn't help because that SpEL is evaluated only once at applicationContext strtup.
Since you are going to change the directory at runtime you should use FileReadingMessageSource.setDirectory from your service. Something like this:
SourcePollingChannelAdapter fileInboundAdapter = (SourcePollingChannelAdapter)context.getApplicationContext().getBean("fileInboundAdapter");
if (fileInboundAdapter.isRunning())
fileInboundAdapter.stop();
FileReadingMessageSource source = (FileReadingMessageSource) context.getApplicationContext().getBean("fileInboundAdapter.source");
source.setDirectory(new File(strOutPath[0]+"/"+strOutPath[1]+"/"+strOutPath[2]+"/"+strOutPath[3]+"/"));
fileInboundAdapter.start();
}
And get rid of that AtomicReference.
From the start you can use property-placeholder for the directory attribute directly.
How can I make Lucene include results, indexed outside the siteroot eg. stuff based with a root of fx. "/sitecore/content/stuff", but not placed in "/sitecore/content/Home".
Taking a look at SearchManager.cs in "/sitecore modules/LuceneSearch/, the SiteRoot is defined as "SiteCore.Content.Site.Startpath", but making any changes to this file dosent seem to have any affect.
Note:
I am only using the "LuceneResults".ascx & .cs.
----- Question updated, as I narrowed in what the problem might be -----
Im trying to create an index of a specific set of items, for use in a Lucene search.
In web.config, I have specified an index containing:
...
<root>/sitecore/content/Home/Subfolder</root>
...
and that works flawlessly, getting all the subitems when doen a search.
I have then copied exactly the same items to a new location, and updated my web.config as following:
...
<root>/sitecore/content/newSubfolder/Subfolder/Subfolder</root>
...
Now my searches never finds anything!
Does anyone have an idea what could be the problem here.
Note:
- I have rebuild the Search Index db, at every change.
- In "Luke" the index seems fine, and the the search here yields the proper results.
Complete Index:
<index id="faqindex" type="Sitecore.Search.Index, Sitecore.Kernel">
<param desc="name">$(id)</param>
<param desc="folder">__faq</param>
<Analyzer ref="search/analyzer"/>
<locations hint="list:AddCrawler">
<resources type="Sitecore.Search.Crawlers.DatabaseCrawler, Sitecore.Kernel">
<database>master</database>
<root>/sitecore/content/MyContent/Snippets/FAQ</root>
<include hint="list:IncludeTemplate">
<faqblock>{3340AAAE-B2F8-4E22-8B7B-F3EDDB48587E}</faqblock>
</include>
<tags>faqblock</tags>
<boost>1.0</boost>
</resources>
</locations>
</index>
It sounds like you are using the Lucene Search module from Sitecore Marketplace. The code for this module limits the search results to the site root and its children:
public SearchManager(string indexName)
{
SearchIndexName = indexName;
Database database = Factory.GetDatabase("master");
var item = Sitecore.Context.Site.StartPath;
SiteRoot = database.GetItem(item);
}
[...]
public SearchResultCollection Search(string searchString)
{
//Getting index from the web.config
var searchIndex = Sitecore.Search.SearchManager.GetIndex(SearchIndexName);
using(IndexSearchContext context = searchIndex.CreateSearchContext())
{
SearchHits hits = context.Search(searchString, new SearchContext(SiteRoot));
sitecore modules\Lucene Search\SearchManager.cs
Assuming that the "website" node in the sites section of Web.config has startItem="/home", results outside of the "home" hierarchy will not be returned.
If you download the source code for this project, and edit the line that populates SiteRoot to the following, the new items will be returned:
SiteRoote = database.GetItem("/sitecore/content");
Remember to copy the new LuceneSearch.dll to the bin directory of the website project.
I was trying out MonoTouch/MonoAndroid and everything was going
well until I called IsolatedStorageFile.GetFileNames(string) function. The
parameter was "Foo/Foo1/*". The result is SecurityException with no message.
The directory "Foo/Foo1" exists, because it has just been found using IsolatedStorageFile.GetDirectoryNames() call.
I identified this bit in Mono sources that throws the exception (in IsolatedStorageFile.cs):
DirectoryInfo[] subdirs = directory.GetDirectories (path);
// we're looking for a single result, identical to path (no pattern here)
// we're also looking for something under the current path (not
outside isolated storage)
if ((subdirs.Length == 1) && (subdirs [0].Name == path) && (subdirs[0].FullName.IndexOf(directory.FullName) >= 0)) {
afi = subdirs [0].GetFiles (pattern);
} else {
// CAS, even in FullTrust, normally enforce IsolatedStorage
throw new SecurityException ();
}
I can't step into it with the debugger so I don't know why the
condition is false. This happens both on iOS and Android. There was a
similar issue logged long time ago at
http://www.digipedia.pl/usenet/thread/12492/1724/#post1724, but there
are no replies.
The same code works on Windows Phone 7 without problems (with \ for path separators).
Has anyone got any ideas what might be causing it? Is it the uppercase in
directory names a problem?
It is a bug in Mono. IsolatedStorage will not work with paths that contain more than one directory in a row (such as Foo/Foo1/*)
I copied the code of GetFileNames() method from Mono to my project so that I can debug it. I found out that the problem is in the 2nd term of this condition (IsolatedStorageFile.cs:846):
if ((subdirs.Length == 1) && (subdirs [0].Name == path) &&(subdirs[0].FullName.IndexOf(directory.FullName) >= 0)) {
afi = subdirs [0].GetFiles (pattern);
} else {
// CAS, even in FullTrust, normally enforce IsolatedStorage
throw new SecurityException ();
}
For example when path passed to GetFileNames() is "Foo/Bar/*", subdirs[0].Name will be "Bar" while path will be "Foo/Bar" and the condition will fail causing the exception.