{"action":"created","comment":{"url":"https://api.github.com/repos/spring-projects/spring-integration/pulls/comments/49791837","id":49791837,"diff_hunk":"@@ -608,4 +730,216 @@ else if (destinationDirectoryToUse instanceof File) {\n \t\treturn destinationDirectory;\n \t}\n \n+\tprivate synchronized FileState getFileState(final File fileToWriteTo, boolean isString)\n+\t\t\tthrows FileNotFoundException {\n+\t\tString absolutePath = fileToWriteTo.getAbsolutePath();\n+\t\tFileState state;\n+\t\tboolean appendNoFlush = FileExistsMode.APPEND_NO_FLUSH.equals(this.fileExistsMode);\n+\t\tif (appendNoFlush) {\n+\t\t\tstate = this.fileStates.get(absolutePath);\n+\t\t\tif (state != null && ((isString && state.stream != null) || (!isString && state.writer != null))) {\n+\t\t\t\tstate.close();\n+\t\t\t\tstate = null;\n+\t\t\t\tthis.fileStates.remove(absolutePath);\n+\t\t\t}\n+\t\t\tif (state == null) {\n+\t\t\t\tif (isString) {\n+\t\t\t\t\tstate = new FileState(createWriter(fileToWriteTo, true));\n+\t\t\t\t}\n+\t\t\t\telse {\n+\t\t\t\t\tstate = new FileState(createOutputStream(fileToWriteTo, true));\n+\t\t\t\t}\n+\t\t\t\tthis.fileStates.put(absolutePath, state);\n+\t\t\t}\n+\t\t\tstate.lastWrite = Long.MAX_VALUE; // prevent flush while we write\n+\t\t}\n+\t\telse {\n+\t\t\tstate = null;\n+\t\t}\n+\t\treturn state;\n+\t}\n+\n+\tprivate BufferedWriter createWriter(final File fileToWriteTo, final boolean append) throws FileNotFoundException {\n+\t\treturn new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileToWriteTo, append), this.charset),\n+\t\t\t\tthis.bufferSize);\n+\t}\n+\n+\tprivate BufferedOutputStream createOutputStream(File fileToWriteTo, final boolean append)\n+\t\t\tthrows FileNotFoundException {\n+\t\treturn new BufferedOutputStream(new FileOutputStream(fileToWriteTo, append), this.bufferSize);\n+\t}\n+\n+\t/**\n+\t * When using {@link FileExistsMode#APPEND_NO_FLUSH}, you can send a message to this\n+\t * method to flush any file(s) that needs it. By default, the payload must be a regular\n+\t * expression ({@link String} or {@link Pattern}) that matches the absolutePath\n+\t * of any in-process files. However, if a custom {@link MessageFlushPredicate} is provided,\n+\t * the payload can be of any type supported by that implementation.\n+\t * @since 4.3\n+\t */\n+\t@Override\n+\tpublic synchronized void trigger(Message<?> message) {\n+\t\tflushIfNeeded(this.flushPredicate, message);\n+\t}\n+\n+\t/**\n+\t * When using {@link FileExistsMode#APPEND_NO_FLUSH} you can invoke this method to\n+\t * selectively flush open files. For each open file the supplied\n+\t * {@link MessageFlushPredicate#shouldFlush(String, long, Message)}\n+\t * method is invoked and if true is returned, the file is flushed.\n+\t * @param flushPredicate the {@link FlushPredicate}.\n+\t * @since 4.3\n+\t */\n+\tpublic void flushIfNeeded(FlushPredicate flushPredicate) {\n+\t\tIterator<Entry<String, FileState>> iterator = FileWritingMessageHandler.this.fileStates.entrySet().iterator();\n+\t\twhile (iterator.hasNext()) {\n+\t\t\tEntry<String, FileState> entry = iterator.next();\n+\t\t\tFileState state = entry.getValue();\n+\t\t\tif (flushPredicate.shouldFlush(entry.getKey(), state.lastWrite)) {\n+\t\t\t\titerator.remove();\n+\t\t\t\tstate.close();\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\t/**\n+\t * When using {@link FileExistsMode#APPEND_NO_FLUSH} you can invoke this method to\n+\t * selectively flush open files. For each open file the supplied\n+\t * {@link MessageFlushPredicate#shouldFlush(String, long, Message)}\n+\t * method is invoked and if true is returned, the file is flushed.\n+\t * @param flushPredicate the {@link MessageFlushPredicate}.\n+\t * @param filterMessage an optional message passed into the predicate.\n+\t * @since 4.3\n+\t */\n+\tpublic void flushIfNeeded(MessageFlushPredicate flushPredicate, Message<?> filterMessage) {\n+\t\tIterator<Entry<String, FileState>> iterator = FileWritingMessageHandler.this.fileStates.entrySet().iterator();\n+\t\twhile (iterator.hasNext()) {\n+\t\t\tEntry<String, FileState> entry = iterator.next();\n+\t\t\tFileState state = entry.getValue();\n+\t\t\tif (flushPredicate.shouldFlush(entry.getKey(), state.lastWrite, filterMessage)) {\n+\t\t\t\titerator.remove();\n+\t\t\t\tstate.close();\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\n+\tprivate static final class FileState {\n+\n+\t\tprivate final BufferedWriter writer;\n+\n+\t\tprivate final BufferedOutputStream  stream;\n+\n+\t\tprivate volatile long lastWrite;\n+\n+\t\tprivate FileState(BufferedWriter writer) {\n+\t\t\tthis.writer = writer;\n+\t\t\tthis.stream = null;\n+\t\t}\n+\n+\t\tprivate FileState(BufferedOutputStream stream) {\n+\t\t\tthis.writer = null;\n+\t\t\tthis.stream = stream;\n+\t\t}\n+\n+\t\tprivate void close() {\n+\t\t\ttry {\n+\t\t\t\tif (this.writer != null) {\n+\t\t\t\t\tthis.writer.close();\n+\t\t\t\t}\n+\t\t\t\telse {\n+\t\t\t\t\tthis.stream.close();\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tcatch (IOException e) {\n+\t\t\t\t;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tprivate final class Flusher implements Runnable {\n+\n+\t\t@Override\n+\t\tpublic void run() {\n+\t\t\tsynchronized (FileWritingMessageHandler.this) {\n+\t\t\t\tlong expired = FileWritingMessageHandler.this.flushTask == null ? Long.MAX_VALUE\n+\t\t\t\t\t\t: (System.currentTimeMillis() - FileWritingMessageHandler.this.flushInterval);\n+\t\t\t\tIterator<Entry<String, FileState>> iterator = FileWritingMessageHandler.this.fileStates.entrySet().iterator();\n+\t\t\t\twhile (iterator.hasNext()) {\n+\t\t\t\t\tEntry<String, FileState> entry = iterator.next();\n+\t\t\t\t\tFileState state = entry.getValue();\n+\t\t\t\t\tif (state.lastWrite < expired) {","path":"spring-integration-file/src/main/java/org/springframework/integration/file/FileWritingMessageHandler.java","position":471,"original_position":471,"commit_id":"53ac0a02d7cd0d39f5fbf6ead1833dc81efbcca2","original_commit_id":"53ac0a02d7cd0d39f5fbf6ead1833dc81efbcca2","user":{"login":"artembilan","id":1071590,"avatar_url":"https://avatars.githubusercontent.com/u/1071590?v=3","gravatar_id":"","url":"https://api.github.com/users/artembilan","html_url":"https://github.com/artembilan","followers_url":"https://api.github.com/users/artembilan/followers","following_url":"https://api.github.com/users/artembilan/following{/other_user}","gists_url":"https://api.github.com/users/artembilan/gists{/gist_id}","starred_url":"https://api.github.com/users/artembilan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/artembilan/subscriptions","organizations_url":"https://api.github.com/users/artembilan/orgs","repos_url":"https://api.github.com/users/artembilan/repos","events_url":"https://api.github.com/users/artembilan/events{/privacy}","received_events_url":"https://api.github.com/users/artembilan/received_events","type":"User","site_admin":false},"body":"I wonder if there is some tiny case, when we `stop()` adapter and create a new `FileState`:\r\n> state.lastWrite = Long.MAX_VALUE; // prevent flush while we write\r\n\r\nSo, it won't be flashed/closed.\r\nMaybe `state.lastWrite <= expired` would be better ?","created_at":"2016-01-14T21:59:41Z","updated_at":"2016-01-14T21:59:41Z","html_url":"https://github.com/spring-projects/spring-integration/pull/1682#discussion_r49791837","pull_request_url":"https://api.github.com/repos/spring-projects/spring-integration/pulls/1682","_links":{"self":{"href":"https://api.github.com/repos/spring-projects/spring-integration/pulls/comments/49791837"},"html":{"href":"https://github.com/spring-projects/spring-integration/pull/1682#discussion_r49791837"},"pull_request":{"href":"https://api.github.com/repos/spring-projects/spring-integration/pulls/1682"}}},"pull_request":{"url":"https://api.github.com/repos/spring-projects/spring-integration/pulls/1682","id":55820548,"html_url":"https://github.com/spring-projects/spring-integration/pull/1682","diff_url":"https://github.com/spring-projects/spring-integration/pull/1682.diff","patch_url":"https://github.com/spring-projects/spring-integration/pull/1682.patch","issue_url":"https://api.github.com/repos/spring-projects/spring-integration/issues/1682","number":1682,"state":"open","locked":false,"title":"INT-3574: File Outbound - Don't Flush File","user":{"login":"garyrussell","id":483832,"avatar_url":"https://avatars.githubusercontent.com/u/483832?v=3","gravatar_id":"","url":"https://api.github.com/users/garyrussell","html_url":"https://github.com/garyrussell","followers_url":"https://api.github.com/users/garyrussell/followers","following_url":"https://api.github.com/users/garyrussell/following{/other_user}","gists_url":"https://api.github.com/users/garyrussell/gists{/gist_id}","starred_url":"https://api.github.com/users/garyrussell/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/garyrussell/subscriptions","organizations_url":"https://api.github.com/users/garyrussell/orgs","repos_url":"https://api.github.com/users/garyrussell/repos","events_url":"https://api.github.com/users/garyrussell/events{/privacy}","received_events_url":"https://api.github.com/users/garyrussell/received_events","type":"User","site_admin":false},"body":"JIRA: https://jira.spring.io/browse/INT-3574\r\n\r\nInitial commit.","created_at":"2016-01-12T21:36:04Z","updated_at":"2016-01-14T21:59:41Z","closed_at":null,"merged_at":null,"merge_commit_sha":"b4f855983c4757dc0d5e7c8b8a4d6e16dbc84160","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/spring-projects/spring-integration/pulls/1682/commits","review_comments_url":"https://api.github.com/repos/spring-projects/spring-integration/pulls/1682/comments","review_comment_url":"https://api.github.com/repos/spring-projects/spring-integration/pulls/comments{/number}","comments_url":"https://api.github.com/repos/spring-projects/spring-integration/issues/1682/comments","statuses_url":"https://api.github.com/repos/spring-projects/spring-integration/statuses/53ac0a02d7cd0d39f5fbf6ead1833dc81efbcca2","head":{"label":"garyrussell:INT-3574","ref":"INT-3574","sha":"53ac0a02d7cd0d39f5fbf6ead1833dc81efbcca2","user":{"login":"garyrussell","id":483832,"avatar_url":"https://avatars.githubusercontent.com/u/483832?v=3","gravatar_id":"","url":"https://api.github.com/users/garyrussell","html_url":"https://github.com/garyrussell","followers_url":"https://api.github.com/users/garyrussell/followers","following_url":"https://api.github.com/users/garyrussell/following{/other_user}","gists_url":"https://api.github.com/users/garyrussell/gists{/gist_id}","starred_url":"https://api.github.com/users/garyrussell/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/garyrussell/subscriptions","organizations_url":"https://api.github.com/users/garyrussell/orgs","repos_url":"https://api.github.com/users/garyrussell/repos","events_url":"https://api.github.com/users/garyrussell/events{/privacy}","received_events_url":"https://api.github.com/users/garyrussell/received_events","type":"User","site_admin":false},"repo":{"id":2197787,"name":"spring-integration","full_name":"garyrussell/spring-integration","owner":{"login":"garyrussell","id":483832,"avatar_url":"https://avatars.githubusercontent.com/u/483832?v=3","gravatar_id":"","url":"https://api.github.com/users/garyrussell","html_url":"https://github.com/garyrussell","followers_url":"https://api.github.com/users/garyrussell/followers","following_url":"https://api.github.com/users/garyrussell/following{/other_user}","gists_url":"https://api.github.com/users/garyrussell/gists{/gist_id}","starred_url":"https://api.github.com/users/garyrussell/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/garyrussell/subscriptions","organizations_url":"https://api.github.com/users/garyrussell/orgs","repos_url":"https://api.github.com/users/garyrussell/repos","events_url":"https://api.github.com/users/garyrussell/events{/privacy}","received_events_url":"https://api.github.com/users/garyrussell/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/garyrussell/spring-integration","description":"","fork":true,"url":"https://api.github.com/repos/garyrussell/spring-integration","forks_url":"https://api.github.com/repos/garyrussell/spring-integration/forks","keys_url":"https://api.github.com/repos/garyrussell/spring-integration/keys{/key_id}","collaborators_url":"https://api.github.com/repos/garyrussell/spring-integration/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/garyrussell/spring-integration/teams","hooks_url":"https://api.github.com/repos/garyrussell/spring-integration/hooks","issue_events_url":"https://api.github.com/repos/garyrussell/spring-integration/issues/events{/number}","events_url":"https://api.github.com/repos/garyrussell/spring-integration/events","assignees_url":"https://api.github.com/repos/garyrussell/spring-integration/assignees{/user}","branches_url":"https://api.github.com/repos/garyrussell/spring-integration/branches{/branch}","tags_url":"https://api.github.com/repos/garyrussell/spring-integration/tags","blobs_url":"https://api.github.com/repos/garyrussell/spring-integration/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/garyrussell/spring-integration/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/garyrussell/spring-integration/git/refs{/sha}","trees_url":"https://api.github.com/repos/garyrussell/spring-integration/git/trees{/sha}","statuses_url":"https://api.github.com/repos/garyrussell/spring-integration/statuses/{sha}","languages_url":"https://api.github.com/repos/garyrussell/spring-integration/languages","stargazers_url":"https://api.github.com/repos/garyrussell/spring-integration/stargazers","contributors_url":"https://api.github.com/repos/garyrussell/spring-integration/contributors","subscribers_url":"https://api.github.com/repos/garyrussell/spring-integration/subscribers","subscription_url":"https://api.github.com/repos/garyrussell/spring-integration/subscription","commits_url":"https://api.github.com/repos/garyrussell/spring-integration/commits{/sha}","git_commits_url":"https://api.github.com/repos/garyrussell/spring-integration/git/commits{/sha}","comments_url":"https://api.github.com/repos/garyrussell/spring-integration/comments{/number}","issue_comment_url":"https://api.github.com/repos/garyrussell/spring-integration/issues/comments{/number}","contents_url":"https://api.github.com/repos/garyrussell/spring-integration/contents/{+path}","compare_url":"https://api.github.com/repos/garyrussell/spring-integration/compare/{base}...{head}","merges_url":"https://api.github.com/repos/garyrussell/spring-integration/merges","archive_url":"https://api.github.com/repos/garyrussell/spring-integration/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/garyrussell/spring-integration/downloads","issues_url":"https://api.github.com/repos/garyrussell/spring-integration/issues{/number}","pulls_url":"https://api.github.com/repos/garyrussell/spring-integration/pulls{/number}","milestones_url":"https://api.github.com/repos/garyrussell/spring-integration/milestones{/number}","notifications_url":"https://api.github.com/repos/garyrussell/spring-integration/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/garyrussell/spring-integration/labels{/name}","releases_url":"https://api.github.com/repos/garyrussell/spring-integration/releases{/id}","created_at":"2011-08-12T15:45:00Z","updated_at":"2015-05-05T14:02:54Z","pushed_at":"2016-01-14T21:51:15Z","git_url":"git://github.com/garyrussell/spring-integration.git","ssh_url":"git@github.com:garyrussell/spring-integration.git","clone_url":"https://github.com/garyrussell/spring-integration.git","svn_url":"https://github.com/garyrussell/spring-integration","homepage":"","size":33701,"stargazers_count":2,"watchers_count":2,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":0,"forks":1,"open_issues":0,"watchers":2,"default_branch":"master"}},"base":{"label":"spring-projects:master","ref":"master","sha":"884aebcb0759187cf7e2c6fa841f2cb4cafe6771","user":{"login":"spring-projects","id":317776,"avatar_url":"https://avatars.githubusercontent.com/u/317776?v=3","gravatar_id":"","url":"https://api.github.com/users/spring-projects","html_url":"https://github.com/spring-projects","followers_url":"https://api.github.com/users/spring-projects/followers","following_url":"https://api.github.com/users/spring-projects/following{/other_user}","gists_url":"https://api.github.com/users/spring-projects/gists{/gist_id}","starred_url":"https://api.github.com/users/spring-projects/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/spring-projects/subscriptions","organizations_url":"https://api.github.com/users/spring-projects/orgs","repos_url":"https://api.github.com/users/spring-projects/repos","events_url":"https://api.github.com/users/spring-projects/events{/privacy}","received_events_url":"https://api.github.com/users/spring-projects/received_events","type":"Organization","site_admin":false},"repo":{"id":2090979,"name":"spring-integration","full_name":"spring-projects/spring-integration","owner":{"login":"spring-projects","id":317776,"avatar_url":"https://avatars.githubusercontent.com/u/317776?v=3","gravatar_id":"","url":"https://api.github.com/users/spring-projects","html_url":"https://github.com/spring-projects","followers_url":"https://api.github.com/users/spring-projects/followers","following_url":"https://api.github.com/users/spring-projects/following{/other_user}","gists_url":"https://api.github.com/users/spring-projects/gists{/gist_id}","starred_url":"https://api.github.com/users/spring-projects/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/spring-projects/subscriptions","organizations_url":"https://api.github.com/users/spring-projects/orgs","repos_url":"https://api.github.com/users/spring-projects/repos","events_url":"https://api.github.com/users/spring-projects/events{/privacy}","received_events_url":"https://api.github.com/users/spring-projects/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/spring-projects/spring-integration","description":"Spring Integration provides an extension of the Spring programming model to support the well-known Enterprise Integration Patterns (EIP)","fork":false,"url":"https://api.github.com/repos/spring-projects/spring-integration","forks_url":"https://api.github.com/repos/spring-projects/spring-integration/forks","keys_url":"https://api.github.com/repos/spring-projects/spring-integration/keys{/key_id}","collaborators_url":"https://api.github.com/repos/spring-projects/spring-integration/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/spring-projects/spring-integration/teams","hooks_url":"https://api.github.com/repos/spring-projects/spring-integration/hooks","issue_events_url":"https://api.github.com/repos/spring-projects/spring-integration/issues/events{/number}","events_url":"https://api.github.com/repos/spring-projects/spring-integration/events","assignees_url":"https://api.github.com/repos/spring-projects/spring-integration/assignees{/user}","branches_url":"https://api.github.com/repos/spring-projects/spring-integration/branches{/branch}","tags_url":"https://api.github.com/repos/spring-projects/spring-integration/tags","blobs_url":"https://api.github.com/repos/spring-projects/spring-integration/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/spring-projects/spring-integration/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/spring-projects/spring-integration/git/refs{/sha}","trees_url":"https://api.github.com/repos/spring-projects/spring-integration/git/trees{/sha}","statuses_url":"https://api.github.com/repos/spring-projects/spring-integration/statuses/{sha}","languages_url":"https://api.github.com/repos/spring-projects/spring-integration/languages","stargazers_url":"https://api.github.com/repos/spring-projects/spring-integration/stargazers","contributors_url":"https://api.github.com/repos/spring-projects/spring-integration/contributors","subscribers_url":"https://api.github.com/repos/spring-projects/spring-integration/subscribers","subscription_url":"https://api.github.com/repos/spring-projects/spring-integration/subscription","commits_url":"https://api.github.com/repos/spring-projects/spring-integration/commits{/sha}","git_commits_url":"https://api.github.com/repos/spring-projects/spring-integration/git/commits{/sha}","comments_url":"https://api.github.com/repos/spring-projects/spring-integration/comments{/number}","issue_comment_url":"https://api.github.com/repos/spring-projects/spring-integration/issues/comments{/number}","contents_url":"https://api.github.com/repos/spring-projects/spring-integration/contents/{+path}","compare_url":"https://api.github.com/repos/spring-projects/spring-integration/compare/{base}...{head}","merges_url":"https://api.github.com/repos/spring-projects/spring-integration/merges","archive_url":"https://api.github.com/repos/spring-projects/spring-integration/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/spring-projects/spring-integration/downloads","issues_url":"https://api.github.com/repos/spring-projects/spring-integration/issues{/number}","pulls_url":"https://api.github.com/repos/spring-projects/spring-integration/pulls{/number}","milestones_url":"https://api.github.com/repos/spring-projects/spring-integration/milestones{/number}","notifications_url":"https://api.github.com/repos/spring-projects/spring-integration/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/spring-projects/spring-integration/labels{/name}","releases_url":"https://api.github.com/repos/spring-projects/spring-integration/releases{/id}","created_at":"2011-07-22T21:47:27Z","updated_at":"2016-01-13T03:42:38Z","pushed_at":"2016-01-14T21:51:16Z","git_url":"git://github.com/spring-projects/spring-integration.git","ssh_url":"git@github.com:spring-projects/spring-integration.git","clone_url":"https://github.com/spring-projects/spring-integration.git","svn_url":"https://github.com/spring-projects/spring-integration","homepage":"http://projects.spring.io/spring-integration/","size":45177,"stargazers_count":408,"watchers_count":408,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":393,"mirror_url":null,"open_issues_count":5,"forks":393,"open_issues":5,"watchers":408,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/spring-projects/spring-integration/pulls/1682"},"html":{"href":"https://github.com/spring-projects/spring-integration/pull/1682"},"issue":{"href":"https://api.github.com/repos/spring-projects/spring-integration/issues/1682"},"comments":{"href":"https://api.github.com/repos/spring-projects/spring-integration/issues/1682/comments"},"review_comments":{"href":"https://api.github.com/repos/spring-projects/spring-integration/pulls/1682/comments"},"review_comment":{"href":"https://api.github.com/repos/spring-projects/spring-integration/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/spring-projects/spring-integration/pulls/1682/commits"},"statuses":{"href":"https://api.github.com/repos/spring-projects/spring-integration/statuses/53ac0a02d7cd0d39f5fbf6ead1833dc81efbcca2"}}}}