Spring Integration + file reading message source _ Inbound Channel Adapter + Outbound Gateway - file

For File reading message source Inbound Adapter and transformer
with annotations is configured as below
#Bean
#InboundChannelAdapter(autoStartup = "false", value = "incomingchannel", poller = #Poller("custompoller"))
public MessageSource<File> fileReadingMessageSource() {
}
#Transformer(inputChannel = "incomingchannel", outputChannel = "jobLaunchChannel")
public JobLaunchRequest toRequest(Message<File> message) throws Exception {
}
Now I want to change the Transformer to refer to a reply channel of outbound gateway i.e. which moves the files from one directory to another directory i.e. move the file from incomingchannel directory to a different directory and the process or transform he file or perform some validations
<file:outbound-gateway id="mover" request-channel="incomingchannel" reply-channel="newdirectory" directory="<<path to new directory file to be moved" delete-source-files="true"/>
Anyone has converted above XML configuration to annotation configurations or any ideas?
After annotation configurations I will have to change the transformer input channel to refer to newdirectory channel i.e. which is a reply channel of messaging gateway...
Thanks in advance for any help ot suggestions regarding this
--- Update 1 after trying out the snippet provided in link by Artem
#Bean
#ServiceActivator(inputChannel = "incomingchannel")
public MessageHandler fileWritingMessageHandler() {
FileWritingMessageHandler handler = new FileWritingMessageHandler(new File(newdirectorypath));
handler.setFileExistsMode(FileExistsMode.APPEND);
handler.setDeleteSourceFiles(true);
return handler;
}
#MessagingGateway(defaultRequestChannel = "incomingchannel", defaultReplyChannel = "newdirectorychannel")
public interface MyGateway {
void writeToFile(#Header(FileHeaders.FILENAME) String fileName, #Header(FileHeaders.FILENAME) File directory,
String data);
}
But there are two problems encountered
Inbound Adapter is trying to poll the directory also as file (Recursive Directory scanner is used) - How to ensure that directory is not polled as a file
nested exception is org.springframework.messaging.core.DestinationResolutionException: no output-channel or replyChannel header available, failedMessage=GenericMessage [payload=C

Ok. Since it looks like you would like to place the FileWritingMessageHandler after #InboundChannelAdapter and before #Transformer, so this should like:
#Bean
#InboundChannelAdapter(autoStartup = "false", value = "incomingchannel", poller = #Poller("custompoller"))
public MessageSource<File> fileReadingMessageSource() {
}
#Bean
#ServiceActivator(inputChannel = "incomingchannel")
public MessageHandler fileWritingMessageHandler() {
FileWritingMessageHandler handler = new FileWritingMessageHandler(new File(newdirectorypath));
handler.setFileExistsMode(FileExistsMode.APPEND);
handler.setDeleteSourceFiles(true);
handler.setOutputChannelName("jobLaunchTransfromerCannel");
return handler;
}
#Transformer(inputChannel = "jobLaunchTransfromerCannel", outputChannel = "jobLaunchChannel")
public JobLaunchRequest toRequest(Message<File> message) throws Exception {
}
This way an #InboundChannelAdapter sends a File into a FileWritingMessageHandler for its logic, which produces a result file for the next in flow #Transformer to convert a result file into a JobLaunchRequest. And only after that a message is going to be sent to the jobLaunchChannel to file a Spring Batch Job.

Related

Spring Integration + Inbound channel adapter + Recursive directory scanner

Inbound channel adapter is created with a poller to poll files present in root directory and its sub directories
e.g.
RootDir
|_abc.txt
|_subdirectory1
|_subdirfile1.doc
The problem is inbound channel adapter is reading the directory also as message
#Bean
#InboundChannelAdapter(autoStartup = "false", value = "incomingchannel", poller = #Poller("custompoller"))
public MessageSource<File> fileReadingMessageSource(DirectoryScanner directoryScanner) {
FileReadingMessageSource sourceReader = new FileReadingMessageSource();
sourceReader.setScanner(directoryScanner);
}
#Bean
public DirectoryScanner directoryScanner() {
DirectoryScanner scanner = new RecursiveDirectoryScanner();
CompositeFileListFilter filter = new CompositeFileListFilter<>(
Arrays.asList(new AcceptOnceFileListFilter<>(), new RegexPatternFileListFilter(regex)));
scanner.setFilter(filter);
return scanner;
}
#Trasnformer(inputChannel="incomingchannel",....
torequest(Mesage<File> message) {
message.getPayload()
}
Here message.getpayLoad is printing subdirectory1 i.e. directory is also read as a file message
I can handle explicitly as file is directory or not in trasnformer and ignore, but wanted to know is there any way it can be filtered in Recursive Directory scanner attached to Inbound Channel adapter ?
This problem is probably related to this SO thread: Spring Integration + file reading message source _ Inbound Channel Adapter + Outbound Gateway.
You need to think twice if you are OK loosing file tree. It sounded for me that you would like to restore a tree in the FileWritingMessageHandler. So, it is probably better to #Filter messages with directory payload before sending to that transformer.
If you still want to skip dirs from the producing, consider to use a ChainFileListFilter instead of CompositeFileListFilter and configure a RegexPatternFileListFilter first.
This way a filtered directory from the RegexPatternFileListFilter (it is skipped by default see AbstractDirectoryAwareFileListFilter) won't go to the AcceptOnceFileListFilter at all. In your current configuration the AcceptOnceFileListFilter being first accepts a directory and really ignores the next filter in the composition.
UPDATE
What I mean should be like this:
#Bean
public DirectoryScanner directoryScanner() {
DirectoryScanner scanner = new RecursiveDirectoryScanner();
ChainFileListFilter filter = new ChainFileListFilter<>(
Arrays.asList(new RegexPatternFileListFilter(regex), new AcceptOnceFileListFilter<>()));
scanner.setFilter(filter);
return scanner;
}
Nothing more. As long as your regex is just for files, any sub-directory would be skipped and not allowed to go downstream.

Create Event-Driven Consumer on File Endpoint without RouteBuilder in Camel 2.24

I want to run a processor upon file appearance in a directory. My file url is like this:
file:{{file.root}}in?include=.*\.csv&charset=windows-1251&move=../out/done
A procedure that associates an url with a processor is like this:
MessageProcessor getOrCreateConsumer(CamelContext context, String uri) {
Endpoint endpoint = context.getEndpoint(uri);
endpoint.setCamelContext(context); // added this out of desperation, doesn't help
processor = new MessageProcessor();
try {
Consumer consumer = endpoint.createConsumer(processor);
endpoint.start(); // do we need this at all? works the same without it
consumer.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
return processor;
}
}
MessageProcessor is a processor that does some things to an exchange.
Everything seems to work except the file doesn't get moved to the ../out/done directory. While debugging I can't get when the endpoint is configured to provide the file message exchange with this post operation.
I think I am missing some magic call that is normally invoked by a RouteBuilder and that will fully configure the file endpoint. Can you please help me out?

How to upload file to remote FTP Server in grails

I am new to Grails framework. I have a requirement to upload text file to remote FTP Server through batch application in Grails. Request if anyone has a suggestion, step by step process to how to connect to remote server and upload the file.
Thanks in advance.
First, include commons-net in your BuildConfig.groovy (Grails 2.x) or build.gradle (Grails 3.x):
compile 'commons-net:commons-net:3.3'
Secondly add a service:
class UploadService {
GrailsApplication grailsApplication
String upload(String fileName, InputStream inputStream) {
String status
new FTPClient().with {
connect grailsApplication.config.getProperty('ftp.host')
login grailsApplication.config.getProperty('ftp.username'), grailsApplication.config.getProperty('ftp.password')
enterLocalPassiveMode()
setFileType(BINARY_FILE_TYPE)
changeWorkingDirectory grailsApplication.config.getProperty('ftp.uploadDir')
storeFile(fileName, inputStream)
status = replyString
disconnect()
}
return status
}
}
Update:
I forgot to add the configuration that needs to go into grails-app/conf/Config.groovy (Grails 2.x) or grails-app/config/application.groovy:
ftp {
host = 'some.host'
username = 'myuser'
password = '*****'
uploadDir = 'Uploads'
}
It would also be possible to create the FTPClient() instance in resources.groovy and use dependency injection instead.
bean = {
ftpClient(FTPClient)
}
and then have this in the service:
class UploadService {
GrailsApplication grailsApplication
FTPClient ftpClient // Will be injected
String upload(String fileName, InputStream inputStream) {
String status
ftpClient.with {
// Same as above
}
}
}
Which would allow you to unit-test the class, where you simply mock out FTPClient

GWT: form post works only on the local server, not with the app engine

i have a form with a FormPanel, a FileUpload and a Button
final FormPanel formPanel = new FormPanel();
formPanel.setAction("uploadServlet");
formPanel.setMethod(FormPanel.METHOD_POST);
formPanel.setEncoding(FormPanel.ENCODING_MULTIPART);
formPanel.setSize("100%", "100%");
setWidget(formPanel);
AbsolutePanel absolutePanel = new AbsolutePanel();
formPanel.setWidget(absolutePanel);
absolutePanel.setSize("249px", "70px");
final FileUpload fileUpload = new FileUpload();
fileUpload.setName("uploadFormElement");
absolutePanel.add(fileUpload, 0, 0);
Button btnOpen = new Button("Open");
absolutePanel.add(btnOpen, 10, 30);
Button btnCancel = new Button("Cancel");
absolutePanel.add(btnCancel, 63, 30);
this.setText("Open...");
this.setTitle(this.getText());
this.setAnimationEnabled(true);
this.setGlassEnabled(true);
btnOpen.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
formPanel.submit();
}
});
the servlet gets called but the request contains a error message "error post".
When i try it on the local server it works, the request contains the file, but on the app engine server only the error
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List<?> items = null;
String json = null;
try {
items = upload.parseRequest(request);
}
catch (FileUploadException e) {
e.printStackTrace();
}
Iterator<?> it = items.iterator();
while (it.hasNext()) {
System.out.println("while (it.hasNext()) {");
FileItem item = (FileItem) it.next();
json = item.getString();
}
response.setContentType("text/html");
ServletOutputStream out = response.getOutputStream();
response.setContentLength(json.length());
out.write(json.getBytes());
out.close();
}
DiskFileItemFactory is the default implementation for the commons-fileupload library, and based in it's javadoc:
This implementation creates FileItem instances which keep their content either in memory, for smaller items, or in a temporary file on disk, for larger items. The size threshold, above which content will be stored on disk, is configurable, as is the directory in which temporary files will be created.
If not otherwise configured, the default configuration values are as follows:
Size threshold is 10KB. Repository is the system default temp directory, as returned by System.getProperty("java.io.tmpdir").
So as you see, this implementation is going to write in filesystem when it does not have enough memory.
In GAE, there are many constrains, like the memory you are allow to use, or the prohibition of writing in the filesystem.
Your code should fail in GAE developing mode, but maybe you have not reached the memory limitation, or whatever since GAE dev tries to emulate the same constrains than production server, but it is not identical.
Said, that I could take a look to gwtupload library, they have a servlet for GAE which can save files in different ways: BlobStore, FileApi and MemCache.

GWT: Get URL of file located on server

I am developing an web application which can upload/download a file from client to PostgreSQL database server via GWT RPC call.
I managed to create an upload servlet which store desired file(choosed by user via FileUpload widget) to Glassfish "TEMP" directory => then i used SQL command:
INSERT INTO table VALUES ('"+name+"',lo_import('"+f.getCanonicalPath()+"\\TEMP\\"+name+"'),...)
which put that file into database. This works pretty good.
Problem occurs when i want to download file from server to client. First i need to put the file back to TEMP dir with SQL command lo_export(...) -> this didn't work (some ERROR when creating a server file, permission denied), so i put the file manually to TEMP dir.
Question is how can i display that file which is stored on server in TEMP dir?
my path to glassfish server temp dir:C:\Program Files (x86)\glassfish-3.1\glassfish\domains\domain1\TEMP\example.pdf
when deploying app url looks like: http://localhost:8080/AppName/
i tried something like that: Window.open("http://localhost:8080/AppName/TEMP/example.pdf", "_blank", "enabled")
My CODE:
Client side:
String link = GWT.getModuleBaseURL() + "filedownloadservlet";
Window.open(link,event.getSelectedItem().getText(),"enabled");
so i pass to servlet located on server side a link and a file name...am i right ?
Server side:
public class FileDownloadServlet extends HttpServlet {
private String path = "TEMP//"; // Your absolute path
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String filename = req.getParameter("filename");
System.out.println(filename); // THIS IS NULL value
File userManualFile = new File(path + filename);
// You can fetch a Blob from the database instead.
ServletOutputStream servletOutputStream = resp.getOutputStream();
resp.setContentType("application/pdf");
resp.addHeader("content-disposition", "attachment; filename=skuska.pdf");
FileInputStream fileInputStream = new FileInputStream(userManualFile);
IOUtils.copy(fileInputStream, servletOutputStream);
servletOutputStream.flush();
When i press a file in Tree widget it shows me a new browser window with this error:
java.io.FileNotFoundException: TEMP\null (The system cannot find the file specified)
You cannot download a file with a RPC call. You must use a normal java servlet. You have to write the bytes into the HttpServletResponse. You can get the bytes from the file in the database by doing an SQL query.
This example is done with spring MVC.
#Controller
public class UserManualServlet {
private String path = "..." // Your absolute path
#RequestMapping("/app/usermanual.download")
public void generateInterceptActivationDeactivationReport(HttpServletRequest request, HttpServletResponse response)
throws IOException
{
String filename = request.getParameter("filename");
File userManualFile = new File(path + filename);
// You can fetch a Blob from the database instead.
ServletOutputStream servletOutputStream = response.getOutputStream();
response.setContentType("application/pdf");
response.addHeader("content-disposition", "attachment; filename=\"user-manual.pdf\"");
FileInputStream fileInputStream = new FileInputStream(userManualFile);
IOUtils.copy(fileInputStream, servletOutputStream);
servletOutputStream.flush();
}
In this example, you can call the URL : ../app/usermanual.download?filename=usermanual.pdf to download the file.

Resources