{"action":"created","comment":{"url":"https://api.github.com/repos/spring-projects/spring-integration/pulls/comments/36424284","id":36424284,"diff_hunk":"@@ -0,0 +1,192 @@\n+/*\n+ * Copyright 2015 the original author or authors.\n+ *\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ *      http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+package org.springframework.integration.handler;\n+\n+import java.util.concurrent.ConcurrentHashMap;\n+import java.util.concurrent.ConcurrentMap;\n+import java.util.concurrent.SynchronousQueue;\n+import java.util.concurrent.TimeUnit;\n+\n+import org.springframework.integration.IntegrationMessageHeaderAccessor;\n+import org.springframework.integration.aggregator.CorrelationStrategy;\n+import org.springframework.integration.aggregator.DefaultAggregatingMessageGroupProcessor;\n+import org.springframework.integration.aggregator.HeaderAttributeCorrelationStrategy;\n+import org.springframework.integration.aggregator.MessageGroupProcessor;\n+import org.springframework.integration.store.SimpleMessageGroup;\n+import org.springframework.messaging.Message;\n+import org.springframework.messaging.MessagingException;\n+import org.springframework.util.Assert;\n+\n+/**\n+ * A message handler that suspends the thread until a message with corresponding\n+ * correlation is passed into the {@link #triggerAction(Message) triggerAction} method or\n+ * the timeout occurs. Only one thread with a particular correlation (result of invoking\n+ * the {@link CorrelationStrategy}) can be suspended at a time. If the inbound thread does\n+ * not arrive before the trigger thread, the latter is suspended until it does, or the\n+ * timeout occurs.\n+ * <p>\n+ * The default {@link CorrelationStrategy} is a {@link HeaderAttributeCorrelationStrategy}.\n+ * <p>\n+ * The default output processor is a {@link DefaultAggregatingMessageGroupProcessor}.\n+ *\n+ * @author Gary Russell\n+ * @since 4.2\n+ *\n+ */\n+public class BarrierMessageHandler extends AbstractReplyProducingMessageHandler implements TriggerMessageHandler {\n+\n+\tprivate final ConcurrentMap<Object, SynchronousQueue<Message<?>>> suspensions =\n+\t\t\tnew ConcurrentHashMap<Object, SynchronousQueue<Message<?>>>();\n+\n+\tprivate final ConcurrentMap<Object, Thread> inProcess = new ConcurrentHashMap<Object, Thread>();\n+\n+\tprivate final long timeout;\n+\n+\tprivate final CorrelationStrategy correlationStrategy;\n+\n+\tprivate final MessageGroupProcessor messageGroupProcessor;\n+\n+\t/**\n+\t * Construct an instance with the provided timeout and default correlation and\n+\t * output strategies.\n+\t * @param timeout the timeout in milliseconds.\n+\t */\n+\tpublic BarrierMessageHandler(long timeout) {\n+\t\tthis(new HeaderAttributeCorrelationStrategy(IntegrationMessageHeaderAccessor.CORRELATION_ID),\n+\t\t\t\tnew DefaultAggregatingMessageGroupProcessor(), timeout);\n+\t}\n+\n+\t/**\n+\t * Construct an instance with the provided timeout and output processor, and default\n+\t * correlation strategy.\n+\t * @param timeout the timeout in milliseconds.\n+\t * @param outputProcessor the output {@link MessageGroupProcessor}.\n+\t */\n+\tpublic BarrierMessageHandler(long timeout, MessageGroupProcessor outputProcessor) {\n+\t\tthis(new HeaderAttributeCorrelationStrategy(IntegrationMessageHeaderAccessor.CORRELATION_ID),\n+\t\t\t\toutputProcessor, timeout);\n+\t}\n+\n+\t/**\n+\t * Construct an instance with the provided timeout and correlation strategy, and default\n+\t * output processor.\n+\t * @param timeout the timeout in milliseconds.\n+\t * @param correlationStrategy the correlation strategy.\n+\t */\n+\tpublic BarrierMessageHandler(CorrelationStrategy correlationStrategy, long timeout) {\n+\t\tthis(correlationStrategy, new DefaultAggregatingMessageGroupProcessor(), timeout);\n+\t}\n+\n+\t/**\n+\t * Construct an instance with the provided timeout and output processor, and default\n+\t * correlation strategy.\n+\t * @param timeout the timeout in milliseconds.\n+\t * @param correlationStrategy the correlation strategy.\n+\t * @param outputProcessor the output {@link MessageGroupProcessor}.\n+\t */\n+\tpublic BarrierMessageHandler(CorrelationStrategy correlationStrategy,\n+\t\t\tMessageGroupProcessor outputProcessor, long timeout) {\n+\t\tAssert.notNull(correlationStrategy, \"'correlationStrategy' cannot be null\");\n+\t\tAssert.notNull(outputProcessor, \"'messageGroupProcessor' cannot be null\");\n+\t\tthis.correlationStrategy = correlationStrategy;\n+\t\tthis.messageGroupProcessor =  outputProcessor;\n+\t\tthis.timeout = timeout;\n+\t}\n+\n+\t@Override\n+\tprotected Object handleRequestMessage(Message<?> requestMessage) {\n+\t\tObject key = this.correlationStrategy.getCorrelationKey(requestMessage);\n+\t\tif (key == null) {\n+\t\t\tthrow new MessagingException(requestMessage, \"Correlation Strategy returned null\");\n+\t\t}\n+\t\tThread existing = this.inProcess.putIfAbsent(key, Thread.currentThread());\n+\t\tif (existing != null) {\n+\t\t\tthrow new MessagingException(requestMessage, \"Correlation key (\"\n+\t\t\t\t\t+ key + \") is already in use by \" + existing.getName());\n+\t\t}\n+\t\tSynchronousQueue<Message<?>> syncQueue = createOrObtainQueue(key);\n+\t\ttry {\n+\t\t\tMessage<?> release = syncQueue.poll(this.timeout, TimeUnit.MILLISECONDS);\n+\t\t\tif (release != null) {\n+\t\t\t\treturn processRelease(requestMessage, key, release);\n+\t\t\t}\n+\t\t}\n+\t\tcatch (InterruptedException e) {\n+\t\t\tThread.currentThread().interrupt();\n+\t\t\tthrow new MessagingException(requestMessage, \"Interrupted while waiting for release\", e);\n+\t\t}\n+\t\tfinally {\n+\t\t\tthis.inProcess.remove(key);\n+\t\t\tthis.suspensions.remove(key);\n+\t\t}\n+\t\treturn null;\n+\t}\n+\n+\tprivate Object processRelease(Message<?> requestMessage, Object key, Message<?> release) {\n+\t\tthis.suspensions.remove(key);","path":"spring-integration-core/src/main/java/org/springframework/integration/handler/BarrierMessageHandler.java","position":139,"original_position":139,"commit_id":"9bb5d3df76a3739d3827dd407a6a8bf6246cbd7d","original_commit_id":"9bb5d3df76a3739d3827dd407a6a8bf6246cbd7d","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":"No; it's ok; we're protected by inProcess - but effectively, this one does not free up the key earlier because of `inProcess` so the conclusion is remove this one, I think.","created_at":"2015-08-06T14:59:32Z","updated_at":"2015-08-06T14:59:32Z","html_url":"https://github.com/spring-projects/spring-integration/pull/1533#discussion_r36424284","pull_request_url":"https://api.github.com/repos/spring-projects/spring-integration/pulls/1533","_links":{"self":{"href":"https://api.github.com/repos/spring-projects/spring-integration/pulls/comments/36424284"},"html":{"href":"https://github.com/spring-projects/spring-integration/pull/1533#discussion_r36424284"},"pull_request":{"href":"https://api.github.com/repos/spring-projects/spring-integration/pulls/1533"}}},"pull_request":{"url":"https://api.github.com/repos/spring-projects/spring-integration/pulls/1533","id":41513702,"html_url":"https://github.com/spring-projects/spring-integration/pull/1533","diff_url":"https://github.com/spring-projects/spring-integration/pull/1533.diff","patch_url":"https://github.com/spring-projects/spring-integration/pull/1533.patch","issue_url":"https://api.github.com/repos/spring-projects/spring-integration/issues/1533","number":1533,"state":"open","locked":false,"title":"[REVIEW ONLY] INT-3736: Process Barrier Component","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-3736\r\n\r\nNeeds docs and javadoc","created_at":"2015-08-03T21:49:07Z","updated_at":"2015-08-06T14:59:32Z","closed_at":null,"merged_at":null,"merge_commit_sha":"66fd9ed04c48236f8a563eb53219a0bfda9d0017","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/spring-projects/spring-integration/pulls/1533/commits","review_comments_url":"https://api.github.com/repos/spring-projects/spring-integration/pulls/1533/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/1533/comments","statuses_url":"https://api.github.com/repos/spring-projects/spring-integration/statuses/9bb5d3df76a3739d3827dd407a6a8bf6246cbd7d","head":{"label":"garyrussell:INT-3736","ref":"INT-3736","sha":"9bb5d3df76a3739d3827dd407a6a8bf6246cbd7d","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":"2015-08-05T23:53:30Z","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":37453,"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":1,"forks":1,"open_issues":1,"watchers":2,"default_branch":"master"}},"base":{"label":"spring-projects:master","ref":"master","sha":"2376a558a47531daab85d2fe357a98f84deb93df","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":"2015-08-06T03:25:50Z","pushed_at":"2015-08-06T00:32: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":88880,"stargazers_count":373,"watchers_count":373,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":347,"mirror_url":null,"open_issues_count":4,"forks":347,"open_issues":4,"watchers":373,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/spring-projects/spring-integration/pulls/1533"},"html":{"href":"https://github.com/spring-projects/spring-integration/pull/1533"},"issue":{"href":"https://api.github.com/repos/spring-projects/spring-integration/issues/1533"},"comments":{"href":"https://api.github.com/repos/spring-projects/spring-integration/issues/1533/comments"},"review_comments":{"href":"https://api.github.com/repos/spring-projects/spring-integration/pulls/1533/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/1533/commits"},"statuses":{"href":"https://api.github.com/repos/spring-projects/spring-integration/statuses/9bb5d3df76a3739d3827dd407a6a8bf6246cbd7d"}}}}