{"action":"created","comment":{"url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/pulls/comments/43885635","id":43885635,"diff_hunk":"@@ -0,0 +1,338 @@\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+\n+package org.springframework.cloud.stream.binder.gemfire;\n+\n+import java.util.ArrayList;\n+import java.util.Collections;\n+import java.util.List;\n+import java.util.Map;\n+import java.util.Properties;\n+import java.util.concurrent.ConcurrentHashMap;\n+import java.util.concurrent.ExecutorService;\n+import java.util.concurrent.Executors;\n+import java.util.concurrent.atomic.AtomicLong;\n+\n+import com.gemstone.gemfire.cache.Cache;\n+import com.gemstone.gemfire.cache.CacheFactory;\n+import com.gemstone.gemfire.cache.EntryEvent;\n+import com.gemstone.gemfire.cache.Region;\n+import com.gemstone.gemfire.cache.RegionFactory;\n+import com.gemstone.gemfire.cache.RegionShortcut;\n+import com.gemstone.gemfire.cache.partition.PartitionRegionHelper;\n+import com.gemstone.gemfire.cache.util.CacheListenerAdapter;\n+import org.slf4j.Logger;\n+import org.slf4j.LoggerFactory;\n+\n+import org.springframework.cloud.stream.binder.MessageChannelBinderSupport;\n+import org.springframework.messaging.Message;\n+import org.springframework.messaging.MessageChannel;\n+import org.springframework.messaging.MessageHandler;\n+import org.springframework.messaging.MessagingException;\n+import org.springframework.messaging.SubscribableChannel;\n+import org.springframework.scheduling.concurrent.CustomizableThreadFactory;\n+import org.springframework.util.Assert;\n+\n+\n+/**\n+ * A binder that uses <a href=\"http://gemfire.docs.pivotal.io/\">GemFire</a>\n+ * for message delivery. Spring Cloud Stream modules that are of type\n+ * processor or sink will host buckets for a partitioned region used\n+ * to store {@link Message messages}. This allows for message delivery\n+ * directly to the modules that will process them (as opposed to fetching\n+ * messages from a stand-alone messaging system).\n+ *\n+ * @author Patrick Peralta\n+ */\n+public class GemfireMessageChannelBinder extends MessageChannelBinderSupport {\n+\tprivate static final Logger logger = LoggerFactory.getLogger(GemfireMessageChannelBinder.class);\n+\n+\t/**\n+\t * Postfix for message regions.\n+\t */\n+\tpublic static final String MESSAGES_POSTFIX = \"-messages\";\n+\n+\t/**\n+\t * GemFire peer-to-peer cache.\n+\t */\n+\tprivate volatile Cache cache;\n+\n+\t/**\n+\t * A {@link com.gemstone.gemfire.cache.CacheListener} implementation\n+\t * that is invoked when messages are published to a region.\n+\t */\n+\tprivate final MessageListener messageListener = new MessageListener();\n+\n+\t/**\n+\t * Map of message source names to {@link QueueReader}.\n+\t *\n+\t * @see #bindConsumer(String, MessageChannel, Properties)\n+\t */\n+\tprivate final Map<String, QueueReader> queueReaders = new ConcurrentHashMap<>();\n+\n+\t/**\n+\t * Map of message source names to the dedicated {@link ExecutorService}\n+\t * for reading messages.\n+\t *\n+\t * @see #bindConsumer(String, MessageChannel, Properties)\n+\t */\n+\tprivate final Map<String, ExecutorService> executors = new ConcurrentHashMap<>();\n+\n+\t// todo: make the following fields configurable\n+\n+\t/**\n+\t * Maximum number of messages to be fetched from the region\n+\t * for processing at a time.\n+\t */\n+\tprivate volatile int batchSize = 10000;\n+\n+\t/**\n+\t * Flag to determine if messages should be processed in order.\n+\t */\n+\tprivate volatile boolean inOrder = true;\n+\n+\n+\t@Override\n+\tpublic void afterPropertiesSet() throws Exception {\n+\t\tsuper.afterPropertiesSet();\n+\t\t// todo: obtain properties from the config classes\n+\t\tProperties properties = new Properties();\n+\t\tproperties.put(\"locators\", \"localhost[7777]\");\n+\t\tproperties.put(\"log-level\", \"warning\");\n+\t\tproperties.put(\"mcast-port\", \"0\");\n+\t\t// todo: put application name once we figure out how to get it;\n+\t\t// getApplicationName is returning a null/empty string\n+//\t\tproperties.put(\"name\", super.getApplicationContext().getApplicationName());\n+\t\tthis.cache = new CacheFactory(properties).create();\n+\t}\n+\n+\t/**\n+\t * Create a {@link Region} instance used for consuming {@link Message} objects.\n+\t * This region registers {@link #messageListener} as a cache listener which\n+\t * triggers message consumption when a message is added to the region.\n+\t *\n+\t * @param name name of the message region\n+\t * @return region for consuming messages\n+\t */\n+\tprivate Region<MessageKey, Message<?>> createConsumerMessageRegion(String name)  {\n+\t\tRegionFactory<MessageKey, Message<?>> factory = this.cache.createRegionFactory(RegionShortcut.PARTITION);\n+\t\tfactory.addCacheListener(messageListener);\n+\t\treturn factory.create(name + MESSAGES_POSTFIX);\n+\t}\n+\n+\t/**\n+\t * Create a {@link Region} instance used for publishing {@link Message} objects.\n+\t * This region instance will not store buckets; it is assumed that the regions\n+\t * created by consumers will host buckets.\n+\t *\n+\t * @param name name of the message region\n+\t * @return region for producing messages\n+\t */\n+\tprivate Region<MessageKey, Message<?>> createProducerMessageRegion(String name) {\n+\t\tRegionFactory<MessageKey, Message<?>> factory = this.cache.createRegionFactory(RegionShortcut.PARTITION_PROXY);\n+\t\treturn factory.create(name + MESSAGES_POSTFIX);\n+\t}\n+\n+\t@Override\n+\tpublic void bindConsumer(String name, MessageChannel inboundBindTarget, Properties properties) {\n+\t\tlogger.debug(\"bindConsumer({})\", name);\n+\t\tMessageListener messageListener = new MessageListener();\n+\t\tQueueReader queueReader = new QueueReader(createConsumerMessageRegion(name),\n+\t\t\t\tinboundBindTarget, messageListener, batchSize, inOrder);\n+\t\tthis.queueReaders.put(name, queueReader);\n+\t\tExecutorService service = Executors.newSingleThreadExecutor(\n+\t\t\t\tnew CustomizableThreadFactory(name + \"-QueueReader\"));\n+\t\tthis.executors.put(name, service);\n+\t\tservice.submit(queueReader);\n+\t}\n+\n+\t@Override\n+\tpublic void unbindConsumer(String name, MessageChannel channel) {\n+\t\tthis.queueReaders.remove(name).shutdown();\n+\t\tthis.executors.remove(name).shutdown();\n+\t\tsuper.unbindConsumer(name, channel);\n+\t}\n+\n+\t@Override\n+\tpublic void bindPubSubConsumer(String name, MessageChannel inboundBindTarget, Properties properties) {\n+\t\tlogger.debug(\"bindPubSubConsumer\");\n+\t}\n+\n+\t@Override\n+\tpublic void bindProducer(String name, MessageChannel outboundBindTarget, Properties properties) {\n+\t\tlogger.debug(\"bindProducer({})\", name);\n+\t\tAssert.isInstanceOf(SubscribableChannel.class, outboundBindTarget);\n+\n+\t\t((SubscribableChannel) outboundBindTarget).subscribe(\n+\t\t\t\tnew SendingHandler(createProducerMessageRegion(name),\n+\t\t\t\t\t\tthis.cache.getDistributedSystem().getDistributedMember().getProcessId()));\n+\t}\n+\n+\t@Override\n+\tpublic void bindPubSubProducer(String name, MessageChannel outboundBindTarget, Properties properties) {\n+\t}\n+\n+\t@Override\n+\tpublic void bindRequestor(String name, MessageChannel requests, MessageChannel replies, Properties properties) {\n+\t}\n+\n+\t@Override\n+\tpublic void bindReplier(String name, MessageChannel requests, MessageChannel replies, Properties properties) {\n+\t}\n+\n+\n+\t/**\n+\t * {@link com.gemstone.gemfire.cache.CacheListener} implementation that\n+\t * {@link Object#notifyAll() notifies} itself when a new entry is added\n+\t * to the region it is registered for.\n+\t */\n+\tprivate static class MessageListener extends CacheListenerAdapter<MessageKey, Message<?>> {\n+\n+\t\tpublic MessageListener() {\n+\t\t}\n+\n+\t\t@Override\n+\t\tpublic synchronized void afterCreate(EntryEvent<MessageKey, Message<?>> event) {\n+\t\t\tthis.notifyAll();\n+\t\t}\n+\t}\n+\n+\n+\t/**\n+\t * Reads {@link Message} objects from a {@link Region} and\n+\t * publishes them to a {@link MessageChannel}.\n+\t */\n+\tprivate static class QueueReader implements Runnable {\n+\n+\t\tprivate final Region<MessageKey, Message<?>> messageRegion;\n+\n+\t\tprivate final MessageChannel messageChannel;\n+\n+\t\tprivate final MessageListener messageListener;\n+\n+\t\tprivate final int batchSize;\n+\n+\t\tprivate final boolean inOrder;\n+\n+\t\tprivate volatile boolean running = true;\n+\n+\t\tpublic QueueReader(Region<MessageKey, Message<?>> messageRegion,\n+\t\t\t\tMessageChannel messageChannel, MessageListener messageListener,\n+\t\t\t\tint batchSize, boolean inOrder) {\n+\t\t\tthis.messageRegion = messageRegion;\n+\t\t\tthis.messageChannel = messageChannel;\n+\t\t\tthis.messageListener = messageListener;\n+\t\t\tthis.batchSize = batchSize;\n+\t\t\tthis.inOrder = inOrder;\n+\t\t}\n+\n+\t\tpublic boolean isRunning() {\n+\t\t\treturn this.running;\n+\t\t}\n+\n+\t\tpublic void shutdown() {\n+\t\t\tthis.running = false;\n+\t\t}\n+\n+\t\t@Override\n+\t\tpublic void run() {\n+\t\t\t// only messages that are present in this JVM will be processed\n+\t\t\tRegion<MessageKey, Message<?>> localMessageRegion =\n+\t\t\t\t\tPartitionRegionHelper.getLocalData(this.messageRegion);\n+\n+\t\t\twhile (isRunning()) {\n+\t\t\t\tif (localMessageRegion.isEmpty()) {\n+\t\t\t\t\ttry {\n+\t\t\t\t\t\tsynchronized (this.messageListener) {\n+\t\t\t\t\t\t\tthis.messageListener.wait(100);\n+\t\t\t\t\t\t}\n+\t\t\t\t\t}\n+\t\t\t\t\tcatch (InterruptedException e) {\n+\t\t\t\t\t\tlogger.warn(\"Thread interrupted\", e);\n+\t\t\t\t\t\tThread.currentThread().interrupt();\n+\t\t\t\t\t\tshutdown();\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t\telse {\n+\t\t\t\t\tList<MessageKey> keys = new ArrayList<>(localMessageRegion.keySet());\n+\t\t\t\t\tlogger.debug(\"Fetched {} messages\", keys.size());\n+\n+\t\t\t\t\tif (this.inOrder) {\n+\t\t\t\t\t\tCollections.sort(keys);\n+\t\t\t\t\t}\n+\t\t\t\t\tif (keys.size() > this.batchSize) {\n+\t\t\t\t\t\tkeys = keys.subList(0, this.batchSize);\n+\t\t\t\t\t}\n+\n+\t\t\t\t\tList<MessageKey> errorKeys = null;","path":"spring-cloud-stream-binders/spring-cloud-stream-binder-gemfire/src/main/java/org/springframework/cloud/stream/binder/gemfire/GemfireMessageChannelBinder.java","position":280,"original_position":280,"commit_id":"163a87928bfdb6730acfe088110c7aa195f60de2","original_commit_id":"163a87928bfdb6730acfe088110c7aa195f60de2","user":{"login":"ericbottard","id":313494,"avatar_url":"https://avatars.githubusercontent.com/u/313494?v=3","gravatar_id":"","url":"https://api.github.com/users/ericbottard","html_url":"https://github.com/ericbottard","followers_url":"https://api.github.com/users/ericbottard/followers","following_url":"https://api.github.com/users/ericbottard/following{/other_user}","gists_url":"https://api.github.com/users/ericbottard/gists{/gist_id}","starred_url":"https://api.github.com/users/ericbottard/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ericbottard/subscriptions","organizations_url":"https://api.github.com/users/ericbottard/orgs","repos_url":"https://api.github.com/users/ericbottard/repos","events_url":"https://api.github.com/users/ericbottard/events{/privacy}","received_events_url":"https://api.github.com/users/ericbottard/received_events","type":"User","site_admin":false},"body":"Why not use `clear()` instead if `== null` tests all over the place?","created_at":"2015-11-04T14:25:53Z","updated_at":"2015-11-04T14:25:53Z","html_url":"https://github.com/spring-cloud/spring-cloud-stream/pull/189#discussion_r43885635","pull_request_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/pulls/189","_links":{"self":{"href":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/pulls/comments/43885635"},"html":{"href":"https://github.com/spring-cloud/spring-cloud-stream/pull/189#discussion_r43885635"},"pull_request":{"href":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/pulls/189"}}},"pull_request":{"url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/pulls/189","id":49476609,"html_url":"https://github.com/spring-cloud/spring-cloud-stream/pull/189","diff_url":"https://github.com/spring-cloud/spring-cloud-stream/pull/189.diff","patch_url":"https://github.com/spring-cloud/spring-cloud-stream/pull/189.patch","issue_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/issues/189","number":189,"state":"open","locked":false,"title":"XD-3512: Initial GemFire binder","user":{"login":"pperalta","id":394956,"avatar_url":"https://avatars.githubusercontent.com/u/394956?v=3","gravatar_id":"","url":"https://api.github.com/users/pperalta","html_url":"https://github.com/pperalta","followers_url":"https://api.github.com/users/pperalta/followers","following_url":"https://api.github.com/users/pperalta/following{/other_user}","gists_url":"https://api.github.com/users/pperalta/gists{/gist_id}","starred_url":"https://api.github.com/users/pperalta/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pperalta/subscriptions","organizations_url":"https://api.github.com/users/pperalta/orgs","repos_url":"https://api.github.com/users/pperalta/repos","events_url":"https://api.github.com/users/pperalta/events{/privacy}","received_events_url":"https://api.github.com/users/pperalta/received_events","type":"User","site_admin":false},"body":"Initial implementation of GemFire binder.\r\nSee https://docs.google.com/document/d/18gjwnh50CADCVyfnEh2h5cbgrIZm6n4UYQlaHGQW_QU/edit\r\nfor more details.\r\n\r\nNext steps include:\r\n * Partitioning support\r\n * Configuration support (including cache topologies)\r\n * Automated test suite","created_at":"2015-11-02T19:48:22Z","updated_at":"2015-11-04T14:25:53Z","closed_at":null,"merged_at":null,"merge_commit_sha":"1fd4285d066b57e3e7eba8a545fa49bed355f5a6","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/pulls/189/commits","review_comments_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/pulls/189/comments","review_comment_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/pulls/comments{/number}","comments_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/issues/189/comments","statuses_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/statuses/163a87928bfdb6730acfe088110c7aa195f60de2","head":{"label":"pperalta:gemfire-binder","ref":"gemfire-binder","sha":"163a87928bfdb6730acfe088110c7aa195f60de2","user":{"login":"pperalta","id":394956,"avatar_url":"https://avatars.githubusercontent.com/u/394956?v=3","gravatar_id":"","url":"https://api.github.com/users/pperalta","html_url":"https://github.com/pperalta","followers_url":"https://api.github.com/users/pperalta/followers","following_url":"https://api.github.com/users/pperalta/following{/other_user}","gists_url":"https://api.github.com/users/pperalta/gists{/gist_id}","starred_url":"https://api.github.com/users/pperalta/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pperalta/subscriptions","organizations_url":"https://api.github.com/users/pperalta/orgs","repos_url":"https://api.github.com/users/pperalta/repos","events_url":"https://api.github.com/users/pperalta/events{/privacy}","received_events_url":"https://api.github.com/users/pperalta/received_events","type":"User","site_admin":false},"repo":{"id":41451187,"name":"spring-cloud-stream","full_name":"pperalta/spring-cloud-stream","owner":{"login":"pperalta","id":394956,"avatar_url":"https://avatars.githubusercontent.com/u/394956?v=3","gravatar_id":"","url":"https://api.github.com/users/pperalta","html_url":"https://github.com/pperalta","followers_url":"https://api.github.com/users/pperalta/followers","following_url":"https://api.github.com/users/pperalta/following{/other_user}","gists_url":"https://api.github.com/users/pperalta/gists{/gist_id}","starred_url":"https://api.github.com/users/pperalta/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pperalta/subscriptions","organizations_url":"https://api.github.com/users/pperalta/orgs","repos_url":"https://api.github.com/users/pperalta/repos","events_url":"https://api.github.com/users/pperalta/events{/privacy}","received_events_url":"https://api.github.com/users/pperalta/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/pperalta/spring-cloud-stream","description":"Messaging Microservices with Spring Integration","fork":true,"url":"https://api.github.com/repos/pperalta/spring-cloud-stream","forks_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/forks","keys_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/keys{/key_id}","collaborators_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/teams","hooks_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/hooks","issue_events_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/issues/events{/number}","events_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/events","assignees_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/assignees{/user}","branches_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/branches{/branch}","tags_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/tags","blobs_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/git/refs{/sha}","trees_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/git/trees{/sha}","statuses_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/statuses/{sha}","languages_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/languages","stargazers_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/stargazers","contributors_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/contributors","subscribers_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/subscribers","subscription_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/subscription","commits_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/commits{/sha}","git_commits_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/git/commits{/sha}","comments_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/comments{/number}","issue_comment_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/issues/comments{/number}","contents_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/contents/{+path}","compare_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/compare/{base}...{head}","merges_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/merges","archive_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/downloads","issues_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/issues{/number}","pulls_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/pulls{/number}","milestones_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/milestones{/number}","notifications_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/labels{/name}","releases_url":"https://api.github.com/repos/pperalta/spring-cloud-stream/releases{/id}","created_at":"2015-08-26T21:38:39Z","updated_at":"2015-08-26T21:38:40Z","pushed_at":"2015-11-04T02:32:49Z","git_url":"git://github.com/pperalta/spring-cloud-stream.git","ssh_url":"git@github.com:pperalta/spring-cloud-stream.git","clone_url":"https://github.com/pperalta/spring-cloud-stream.git","svn_url":"https://github.com/pperalta/spring-cloud-stream","homepage":"http://cloud.spring.io/spring-cloud-stream/","size":1821,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"spring-cloud:master","ref":"master","sha":"1b10c8801aa96bda1b5903c8a2b204de9539a7a1","user":{"login":"spring-cloud","id":7815877,"avatar_url":"https://avatars.githubusercontent.com/u/7815877?v=3","gravatar_id":"","url":"https://api.github.com/users/spring-cloud","html_url":"https://github.com/spring-cloud","followers_url":"https://api.github.com/users/spring-cloud/followers","following_url":"https://api.github.com/users/spring-cloud/following{/other_user}","gists_url":"https://api.github.com/users/spring-cloud/gists{/gist_id}","starred_url":"https://api.github.com/users/spring-cloud/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/spring-cloud/subscriptions","organizations_url":"https://api.github.com/users/spring-cloud/orgs","repos_url":"https://api.github.com/users/spring-cloud/repos","events_url":"https://api.github.com/users/spring-cloud/events{/privacy}","received_events_url":"https://api.github.com/users/spring-cloud/received_events","type":"Organization","site_admin":false},"repo":{"id":38764029,"name":"spring-cloud-stream","full_name":"spring-cloud/spring-cloud-stream","owner":{"login":"spring-cloud","id":7815877,"avatar_url":"https://avatars.githubusercontent.com/u/7815877?v=3","gravatar_id":"","url":"https://api.github.com/users/spring-cloud","html_url":"https://github.com/spring-cloud","followers_url":"https://api.github.com/users/spring-cloud/followers","following_url":"https://api.github.com/users/spring-cloud/following{/other_user}","gists_url":"https://api.github.com/users/spring-cloud/gists{/gist_id}","starred_url":"https://api.github.com/users/spring-cloud/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/spring-cloud/subscriptions","organizations_url":"https://api.github.com/users/spring-cloud/orgs","repos_url":"https://api.github.com/users/spring-cloud/repos","events_url":"https://api.github.com/users/spring-cloud/events{/privacy}","received_events_url":"https://api.github.com/users/spring-cloud/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/spring-cloud/spring-cloud-stream","description":"Messaging Microservices with Spring Integration","fork":false,"url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream","forks_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/forks","keys_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/keys{/key_id}","collaborators_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/teams","hooks_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/hooks","issue_events_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/issues/events{/number}","events_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/events","assignees_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/assignees{/user}","branches_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/branches{/branch}","tags_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/tags","blobs_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/git/refs{/sha}","trees_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/git/trees{/sha}","statuses_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/statuses/{sha}","languages_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/languages","stargazers_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/stargazers","contributors_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/contributors","subscribers_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/subscribers","subscription_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/subscription","commits_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/commits{/sha}","git_commits_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/git/commits{/sha}","comments_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/comments{/number}","issue_comment_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/issues/comments{/number}","contents_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/contents/{+path}","compare_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/compare/{base}...{head}","merges_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/merges","archive_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/downloads","issues_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/issues{/number}","pulls_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/pulls{/number}","milestones_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/milestones{/number}","notifications_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/labels{/name}","releases_url":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/releases{/id}","created_at":"2015-07-08T15:51:38Z","updated_at":"2015-11-02T05:38:53Z","pushed_at":"2015-11-04T02:32:49Z","git_url":"git://github.com/spring-cloud/spring-cloud-stream.git","ssh_url":"git@github.com:spring-cloud/spring-cloud-stream.git","clone_url":"https://github.com/spring-cloud/spring-cloud-stream.git","svn_url":"https://github.com/spring-cloud/spring-cloud-stream","homepage":"http://cloud.spring.io/spring-cloud-stream/","size":3464,"stargazers_count":18,"watchers_count":18,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":24,"mirror_url":null,"open_issues_count":37,"forks":24,"open_issues":37,"watchers":18,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/pulls/189"},"html":{"href":"https://github.com/spring-cloud/spring-cloud-stream/pull/189"},"issue":{"href":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/issues/189"},"comments":{"href":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/issues/189/comments"},"review_comments":{"href":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/pulls/189/comments"},"review_comment":{"href":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/pulls/189/commits"},"statuses":{"href":"https://api.github.com/repos/spring-cloud/spring-cloud-stream/statuses/163a87928bfdb6730acfe088110c7aa195f60de2"}}}}