├── .classpath
├── .gitignore
├── .project
├── .settings
└── org.codehaus.groovy.eclipse.preferences.prefs
├── .travis.yml
├── LICENSE.txt
├── README.md
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── grails-app
├── conf
│ ├── application.groovy
│ ├── application.yml
│ └── logback.groovy
├── controllers
│ └── UrlMappings.groovy
├── init
│ └── grails
│ │ └── plugins
│ │ └── rabbitmq
│ │ └── Application.groovy
└── views
│ ├── error.gsp
│ ├── index.gsp
│ ├── layouts
│ └── main.gsp
│ └── notFound.gsp
├── src
├── docs
│ ├── guide
│ │ ├── configuration.gdoc
│ │ ├── configuration
│ │ │ ├── advancedConfig.gdoc
│ │ │ ├── configuringExchanges.gdoc
│ │ │ └── configuringQueues.gdoc
│ │ ├── consumingMessages.gdoc
│ │ ├── consumingMessages
│ │ │ ├── manualQueueManagement.gdoc
│ │ │ ├── messages.gdoc
│ │ │ └── pubSub.gdoc
│ │ ├── introduction.gdoc
│ │ ├── introduction
│ │ │ └── changeLog.gdoc
│ │ ├── links.yml
│ │ ├── rabbitTemplate.gdoc
│ │ ├── rewriteRules.txt
│ │ ├── sendingMessages.gdoc
│ │ └── toc.yml
│ └── ref
│ │ └── All Classes
│ │ └── rabbitSend.gdoc
├── main
│ └── groovy
│ │ └── grails.plugins.rabbitmq
│ │ ├── AutoQueueMessageListenerContainer.groovy
│ │ ├── RabbitConfigurationHolder.groovy
│ │ ├── RabbitDynamicMethods.groovy
│ │ ├── RabbitErrorHandler.groovy
│ │ ├── RabbitQueueBuilder.groovy
│ │ ├── RabbitServiceConfigurer.groovy
│ │ └── RabbitmqGrailsPlugin.groovy
└── test
│ └── groovy
│ └── grails
│ └── plugins
│ └── rabbitmq
│ ├── AutoQueueMessageListenerContainerSpec.groovy
│ ├── RabbitConfigurationHolderSpec.groovy
│ ├── RabbitDynamicMethodsSpec.groovy
│ ├── RabbitGrailsPluginSpec.groovy
│ └── RabbitQueueBuilderSpec.groovy
└── travis-build.sh
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # JetBrains IntelliJ IDEA files
2 | .idea/
3 | *.iml
4 | *.iws
5 | .gradle
6 | build/
7 |
8 | # Log files
9 | *.log
10 |
11 | # Libraries and others
12 | *.zip
13 |
14 | # Target
15 | target/
16 | target-eclipse/
17 |
18 | .DS_Store
19 |
20 | docs/
21 | plugin.xml
22 | .settings
23 |
24 | # Unused grails files
25 | .classpath
26 | .project
27 | test/reports
28 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | rabbitmq
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.wst.common.project.facet.core.builder
10 |
11 |
12 |
13 |
14 | org.eclipse.jdt.core.javabuilder
15 |
16 |
17 |
18 |
19 |
20 | com.springsource.sts.grails.core.nature
21 | org.eclipse.jdt.groovy.core.groovyNature
22 | org.eclipse.jdt.core.javanature
23 | org.eclipse.wst.common.project.facet.core.nature
24 |
25 |
26 |
27 | tomcat-1.3.4-src-groovy
28 | 2
29 | /Users/pledbrook/dev/projects/git/grails-plugins/grails-rabbitmq/target/plugins/tomcat-1.3.4/src/groovy
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/.settings/org.codehaus.groovy.eclipse.preferences.prefs:
--------------------------------------------------------------------------------
1 | #Created by grails
2 | eclipse.preferences.version=1
3 | groovy.dont.generate.class.files=true
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: groovy
2 |
3 | jdk:
4 | - oraclejdk7
5 |
6 | before_install:
7 | - rm -rf ~/.gvm
8 | - curl -s get.gvmtool.net > ~/install_gvm.sh
9 | - chmod 775 ~/install_gvm.sh
10 | - ~/install_gvm.sh
11 | - echo "gvm_auto_answer=true" > ~/.gvm/etc/config
12 | - source ~/.gvm/bin/gvm-init.sh
13 | - gvm install grails $GRAILS_VERSION || true
14 | - chmod 775 ./travis-build.sh
15 |
16 | branches:
17 | only:
18 | - master
19 |
20 | before_script:
21 | - rm -rf target
22 |
23 | script: ./travis-build.sh
24 |
25 | env:
26 | matrix:
27 | - GRAILS_VERSION=3.0.2
28 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | /*
2 | * Apache License
3 | * Version 2.0, January 2004
4 | * http://www.apache.org/licenses/
5 | *
6 | * TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 | *
8 | * 1. Definitions.
9 | *
10 | * "License" shall mean the terms and conditions for use, reproduction,
11 | * and distribution as defined by Sections 1 through 9 of this document.
12 | *
13 | * "Licensor" shall mean the copyright owner or entity authorized by
14 | * the copyright owner that is granting the License.
15 | *
16 | * "Legal Entity" shall mean the union of the acting entity and all
17 | * other entities that control, are controlled by, or are under common
18 | * control with that entity. For the purposes of this definition,
19 | * "control" means (i) the power, direct or indirect, to cause the
20 | * direction or management of such entity, whether by contract or
21 | * otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | * outstanding shares, or (iii) beneficial ownership of such entity.
23 | *
24 | * "You" (or "Your") shall mean an individual or Legal Entity
25 | * exercising permissions granted by this License.
26 | *
27 | * "Source" form shall mean the preferred form for making modifications,
28 | * including but not limited to software source code, documentation
29 | * source, and configuration files.
30 | *
31 | * "Object" form shall mean any form resulting from mechanical
32 | * transformation or translation of a Source form, including but
33 | * not limited to compiled object code, generated documentation,
34 | * and conversions to other media types.
35 | *
36 | * "Work" shall mean the work of authorship, whether in Source or
37 | * Object form, made available under the License, as indicated by a
38 | * copyright notice that is included in or attached to the work
39 | * (an example is provided in the Appendix below).
40 | *
41 | * "Derivative Works" shall mean any work, whether in Source or Object
42 | * form, that is based on (or derived from) the Work and for which the
43 | * editorial revisions, annotations, elaborations, or other modifications
44 | * represent, as a whole, an original work of authorship. For the purposes
45 | * of this License, Derivative Works shall not include works that remain
46 | * separable from, or merely link (or bind by name) to the interfaces of,
47 | * the Work and Derivative Works thereof.
48 | *
49 | * "Contribution" shall mean any work of authorship, including
50 | * the original version of the Work and any modifications or additions
51 | * to that Work or Derivative Works thereof, that is intentionally
52 | * submitted to Licensor for inclusion in the Work by the copyright owner
53 | * or by an individual or Legal Entity authorized to submit on behalf of
54 | * the copyright owner. For the purposes of this definition, "submitted"
55 | * means any form of electronic, verbal, or written communication sent
56 | * to the Licensor or its representatives, including but not limited to
57 | * communication on electronic mailing lists, source code control systems,
58 | * and issue tracking systems that are managed by, or on behalf of, the
59 | * Licensor for the purpose of discussing and improving the Work, but
60 | * excluding communication that is conspicuously marked or otherwise
61 | * designated in writing by the copyright owner as "Not a Contribution."
62 | *
63 | * "Contributor" shall mean Licensor and any individual or Legal Entity
64 | * on behalf of whom a Contribution has been received by Licensor and
65 | * subsequently incorporated within the Work.
66 | *
67 | * 2. Grant of Copyright License. Subject to the terms and conditions of
68 | * this License, each Contributor hereby grants to You a perpetual,
69 | * worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | * copyright license to reproduce, prepare Derivative Works of,
71 | * publicly display, publicly perform, sublicense, and distribute the
72 | * Work and such Derivative Works in Source or Object form.
73 | *
74 | * 3. Grant of Patent License. Subject to the terms and conditions of
75 | * this License, each Contributor hereby grants to You a perpetual,
76 | * worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | * (except as stated in this section) patent license to make, have made,
78 | * use, offer to sell, sell, import, and otherwise transfer the Work,
79 | * where such license applies only to those patent claims licensable
80 | * by such Contributor that are necessarily infringed by their
81 | * Contribution(s) alone or by combination of their Contribution(s)
82 | * with the Work to which such Contribution(s) was submitted. If You
83 | * institute patent litigation against any entity (including a
84 | * cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | * or a Contribution incorporated within the Work constitutes direct
86 | * or contributory patent infringement, then any patent licenses
87 | * granted to You under this License for that Work shall terminate
88 | * as of the date such litigation is filed.
89 | *
90 | * 4. Redistribution. You may reproduce and distribute copies of the
91 | * Work or Derivative Works thereof in any medium, with or without
92 | * modifications, and in Source or Object form, provided that You
93 | * meet the following conditions:
94 | *
95 | * (a) You must give any other recipients of the Work or
96 | * Derivative Works a copy of this License; and
97 | *
98 | * (b) You must cause any modified files to carry prominent notices
99 | * stating that You changed the files; and
100 | *
101 | * (c) You must retain, in the Source form of any Derivative Works
102 | * that You distribute, all copyright, patent, trademark, and
103 | * attribution notices from the Source form of the Work,
104 | * excluding those notices that do not pertain to any part of
105 | * the Derivative Works; and
106 | *
107 | * (d) If the Work includes a "NOTICE" text file as part of its
108 | * distribution, then any Derivative Works that You distribute must
109 | * include a readable copy of the attribution notices contained
110 | * within such NOTICE file, excluding those notices that do not
111 | * pertain to any part of the Derivative Works, in at least one
112 | * of the following places: within a NOTICE text file distributed
113 | * as part of the Derivative Works; within the Source form or
114 | * documentation, if provided along with the Derivative Works; or,
115 | * within a display generated by the Derivative Works, if and
116 | * wherever such third-party notices normally appear. The contents
117 | * of the NOTICE file are for informational purposes only and
118 | * do not modify the License. You may add Your own attribution
119 | * notices within Derivative Works that You distribute, alongside
120 | * or as an addendum to the NOTICE text from the Work, provided
121 | * that such additional attribution notices cannot be construed
122 | * as modifying the License.
123 | *
124 | * You may add Your own copyright statement to Your modifications and
125 | * may provide additional or different license terms and conditions
126 | * for use, reproduction, or distribution of Your modifications, or
127 | * for any such Derivative Works as a whole, provided Your use,
128 | * reproduction, and distribution of the Work otherwise complies with
129 | * the conditions stated in this License.
130 | *
131 | * 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | * any Contribution intentionally submitted for inclusion in the Work
133 | * by You to the Licensor shall be under the terms and conditions of
134 | * this License, without any additional terms or conditions.
135 | * Notwithstanding the above, nothing herein shall supersede or modify
136 | * the terms of any separate license agreement you may have executed
137 | * with Licensor regarding such Contributions.
138 | *
139 | * 6. Trademarks. This License does not grant permission to use the trade
140 | * names, trademarks, service marks, or product names of the Licensor,
141 | * except as required for reasonable and customary use in describing the
142 | * origin of the Work and reproducing the content of the NOTICE file.
143 | *
144 | * 7. Disclaimer of Warranty. Unless required by applicable law or
145 | * agreed to in writing, Licensor provides the Work (and each
146 | * Contributor provides its Contributions) on an "AS IS" BASIS,
147 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | * implied, including, without limitation, any warranties or conditions
149 | * of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | * PARTICULAR PURPOSE. You are solely responsible for determining the
151 | * appropriateness of using or redistributing the Work and assume any
152 | * risks associated with Your exercise of permissions under this License.
153 | *
154 | * 8. Limitation of Liability. In no event and under no legal theory,
155 | * whether in tort (including negligence), contract, or otherwise,
156 | * unless required by applicable law (such as deliberate and grossly
157 | * negligent acts) or agreed to in writing, shall any Contributor be
158 | * liable to You for damages, including any direct, indirect, special,
159 | * incidental, or consequential damages of any character arising as a
160 | * result of this License or out of the use or inability to use the
161 | * Work (including but not limited to damages for loss of goodwill,
162 | * work stoppage, computer failure or malfunction, or any and all
163 | * other commercial damages or losses), even if such Contributor
164 | * has been advised of the possibility of such damages.
165 | *
166 | * 9. Accepting Warranty or Additional Liability. While redistributing
167 | * the Work or Derivative Works thereof, You may choose to offer,
168 | * and charge a fee for, acceptance of support, warranty, indemnity,
169 | * or other liability obligations and/or rights consistent with this
170 | * License. However, in accepting such obligations, You may act only
171 | * on Your own behalf and on Your sole responsibility, not on behalf
172 | * of any other Contributor, and only if You agree to indemnify,
173 | * defend, and hold each Contributor harmless for any liability
174 | * incurred by, or claims asserted against, such Contributor by reason
175 | * of your accepting any such warranty or additional liability.
176 | *
177 | * END OF TERMS AND CONDITIONS
178 | *
179 | * APPENDIX: How to apply the Apache License to your work.
180 | *
181 | * To apply the Apache License to your work, attach the following
182 | * boilerplate notice, with the fields enclosed by brackets "[]"
183 | * replaced with your own identifying information. (Don't include
184 | * the brackets!) The text should be enclosed in the appropriate
185 | * comment syntax for the file format. We also recommend that a
186 | * file or class name and description of purpose be included on the
187 | * same "printed page" as the copyright notice for easier
188 | * identification within third-party archives.
189 | *
190 | * Copyright [yyyy] [name of copyright owner]
191 | *
192 | * Licensed under the Apache License, Version 2.0 (the "License");
193 | * you may not use this file except in compliance with the License.
194 | * You may obtain a copy of the License at
195 | *
196 | * http://www.apache.org/licenses/LICENSE-2.0
197 | *
198 | * Unless required by applicable law or agreed to in writing, software
199 | * distributed under the License is distributed on an "AS IS" BASIS,
200 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | * See the License for the specific language governing permissions and
202 | * limitations under the License.
203 | */
204 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | [](http://travis-ci.org/grails-plugins/grails-rabbitmq)
3 |
4 |
5 | grails-rabbitmq
6 | ===============
7 |
8 | Grails RabbitMQ Plugin
9 |
10 | [Sample Applicatoin](https://github.com/puneetbehl/rabbitmqDemo.git)
11 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext {
3 | grailsVersion = project.grailsVersion
4 | }
5 | repositories {
6 | mavenLocal()
7 | maven { url "https://repo.grails.org/grails/core" }
8 | }
9 | dependencies {
10 | classpath "org.grails:grails-gradle-plugin:$grailsVersion"
11 | }
12 | }
13 |
14 | plugins {
15 | id "io.spring.dependency-management" version "0.5.1.RELEASE"
16 | id "com.jfrog.bintray" version "1.1"
17 | }
18 |
19 | version "2.0.0-SNAPSHOT"
20 | group "org.grails.plugins"
21 |
22 | apply plugin: 'maven-publish'
23 | apply plugin: 'eclipse'
24 | apply plugin: 'idea'
25 | apply plugin: "spring-boot"
26 | apply plugin: "org.grails.grails-plugin"
27 | apply plugin: "org.grails.grails-gsp"
28 | // Used for publishing to central repository, remove if not needed
29 | apply from:'https://raw.githubusercontent.com/grails/grails-profile-repository/master/profiles/plugin/templates/grailsCentralPublishing.gradle'
30 | apply from:'https://raw.githubusercontent.com/grails/grails-profile-repository/master/profiles/plugin/templates/bintrayPublishing.gradle'
31 |
32 | ext {
33 | grailsVersion = project.grailsVersion
34 | gradleWrapperVersion = project.gradleWrapperVersion
35 | }
36 |
37 | sourceCompatibility = 1.7
38 | targetCompatibility = 1.7
39 |
40 |
41 | repositories {
42 | mavenLocal()
43 | mavenCentral()
44 | maven { url "https://repo.grails.org/grails/core" }
45 | }
46 |
47 | dependencyManagement {
48 | imports {
49 | mavenBom "org.grails:grails-bom:$grailsVersion"
50 | }
51 | applyMavenExclusions false
52 | }
53 |
54 | dependencies {
55 | provided 'org.springframework.boot:spring-boot-starter-logging'
56 | provided "org.springframework.boot:spring-boot-starter-actuator"
57 | provided "org.springframework.boot:spring-boot-autoconfigure"
58 | provided "org.springframework.boot:spring-boot-starter-tomcat"
59 |
60 | provided "org.grails:grails-web-boot"
61 | provided "org.grails:grails-dependencies"
62 | provided 'javax.servlet:javax.servlet-api:3.1.0'
63 |
64 | testCompile "org.grails:grails-plugin-testing"
65 |
66 | compile("org.springframework.amqp:spring-rabbit:1.4.5.RELEASE") {
67 | exclude module: 'junit'
68 | exclude module: 'sprint-aop'
69 | exclude module: 'spring-core'
70 | exclude module: 'spring-oxm'
71 | exclude module: 'spring-test'
72 | exclude module: 'spring-tx'
73 | exclude module: 'slf4j-log4j12'
74 | exclude module: 'log4j'
75 | }
76 | runtime 'org.springframework.retry:spring-retry:1.1.2.RELEASE'
77 |
78 | console "org.grails:grails-console"
79 | }
80 |
81 | task wrapper(type: Wrapper) {
82 | gradleVersion = gradleWrapperVersion
83 | }
84 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | grailsVersion=3.0.2
2 | gradleWrapperVersion=2.3
3 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/grails-plugins/grails-rabbitmq/281ef68ce2d008ee35af9c8a31134e329998331d/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Feb 04 17:05:29 CST 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.3-bin.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/grails-app/conf/application.groovy:
--------------------------------------------------------------------------------
1 | grails.doc.authors = 'Jeff Brown, Peter Ledbrook'
2 | grails.doc.license = 'Apache License 2.0'
3 | grails.doc.title = 'RabbitMQ Plugin'
4 | grails.doc.'api.org.springframework.amqp'='http://static.springsource.org/spring-amqp/docs/1.0.x/apidocs'
--------------------------------------------------------------------------------
/grails-app/conf/application.yml:
--------------------------------------------------------------------------------
1 | ---
2 | grails:
3 | profile: web-plugin
4 | codegen:
5 | defaultPackage: grails.plugins.rabbitmq
6 | info:
7 | app:
8 | name: '@info.app.name@'
9 | version: '@info.app.version@'
10 | grailsVersion: '@info.app.grailsVersion@'
11 | spring:
12 | groovy:
13 | template:
14 | check-template-location: false
15 |
16 | ---
17 | grails:
18 | mime:
19 | disable:
20 | accept:
21 | header:
22 | userAgents:
23 | - Gecko
24 | - WebKit
25 | - Presto
26 | - Trident
27 | types:
28 | all: '*/*'
29 | atom: application/atom+xml
30 | css: text/css
31 | csv: text/csv
32 | form: application/x-www-form-urlencoded
33 | html:
34 | - text/html
35 | - application/xhtml+xml
36 | js: text/javascript
37 | json:
38 | - application/json
39 | - text/json
40 | multipartForm: multipart/form-data
41 | rss: application/rss+xml
42 | text: text/plain
43 | hal:
44 | - application/hal+json
45 | - application/hal+xml
46 | xml:
47 | - text/xml
48 | - application/xml
49 | urlmapping:
50 | cache:
51 | maxsize: 1000
52 | controllers:
53 | defaultScope: singleton
54 | converters:
55 | encoding: UTF-8
56 | views:
57 | default:
58 | codec: html
59 | gsp:
60 | encoding: UTF-8
61 | htmlcodec: xml
62 | codecs:
63 | expression: html
64 | scriptlets: html
65 | taglib: none
66 | staticparts: none
67 | hibernate:
68 | cache:
69 | queries: false
70 | ---
71 | dataSource:
72 | pooled: true
73 | jmxExport: true
74 | driverClassName: org.h2.Driver
75 | username: sa
76 | password:
77 |
78 | environments:
79 | development:
80 | dataSource:
81 | dbCreate: create-drop
82 | url: jdbc:h2:mem:devDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
83 | test:
84 | dataSource:
85 | dbCreate: update
86 | url: jdbc:h2:mem:testDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
87 | production:
88 | dataSource:
89 | dbCreate: update
90 | url: jdbc:h2:prodDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
91 | properties:
92 | jmxEnabled: true
93 | initialSize: 5
94 | maxActive: 50
95 | minIdle: 5
96 | maxIdle: 25
97 | maxWait: 10000
98 | maxAge: 600000
99 | timeBetweenEvictionRunsMillis: 5000
100 | minEvictableIdleTimeMillis: 60000
101 | validationQuery: SELECT 1
102 | validationQueryTimeout: 3
103 | validationInterval: 15000
104 | testOnBorrow: true
105 | testWhileIdle: true
106 | testOnReturn: false
107 | jdbcInterceptors: ConnectionState
108 | defaultTransactionIsolation: 2 # TRANSACTION_READ_COMMITTED
109 |
--------------------------------------------------------------------------------
/grails-app/conf/logback.groovy:
--------------------------------------------------------------------------------
1 | import grails.util.BuildSettings
2 | import grails.util.Environment
3 |
4 |
5 | // See http://logback.qos.ch/manual/groovy.html for details on configuration
6 | appender('STDOUT', ConsoleAppender) {
7 | encoder(PatternLayoutEncoder) {
8 | pattern = "%level %logger - %msg%n"
9 | }
10 | }
11 |
12 | root(ERROR, ['STDOUT'])
13 |
14 | if(Environment.current == Environment.DEVELOPMENT) {
15 | def targetDir = BuildSettings.TARGET_DIR
16 | if(targetDir) {
17 |
18 | appender("FULL_STACKTRACE", FileAppender) {
19 |
20 | file = "${targetDir}/stacktrace.log"
21 | append = true
22 | encoder(PatternLayoutEncoder) {
23 | pattern = "%level %logger - %msg%n"
24 | }
25 | }
26 | logger("StackTrace", ERROR, ['FULL_STACKTRACE'], false )
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/grails-app/controllers/UrlMappings.groovy:
--------------------------------------------------------------------------------
1 | class UrlMappings {
2 | static mappings = {
3 | "/$controller/$action?/$id?"{
4 | constraints {
5 | // apply constraints here
6 | }
7 | }
8 | "/"(view:"/index")
9 | "500"(view:'/error')
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/grails-app/init/grails/plugins/rabbitmq/Application.groovy:
--------------------------------------------------------------------------------
1 | package grails.plugins.rabbitmq
2 |
3 | import grails.boot.GrailsApp
4 | import grails.boot.config.GrailsAutoConfiguration
5 |
6 | class Application extends GrailsAutoConfiguration {
7 | static void main(String[] args) {
8 | GrailsApp.run(Application, args)
9 | }
10 | }
--------------------------------------------------------------------------------
/grails-app/views/error.gsp:
--------------------------------------------------------------------------------
1 |
2 |
Tag Libraries: ${grailsApplication.tagLibClasses.size()}
98 |
99 |
Installed Plugins
100 |
101 |
102 |
${plugin.name} - ${plugin.version}
103 |
104 |
105 |
106 |
107 |
Welcome to Grails
108 |
Congratulations, you have successfully started your first Grails application! At the moment
109 | this is the default page, feel free to modify it to either redirect to a controller or display whatever
110 | content you may choose. Below is a list of controllers that are currently deployed in this application,
111 | click on each to execute its default action:
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/docs/guide/configuration.gdoc:
--------------------------------------------------------------------------------
1 | The plugin supports a number of configuration options which all may be expressed in @grails-app/conf/Config.groovy@. A basic configuration might look something like this:
2 |
3 | {code}
4 | // grails-app/conf/Config.groovy
5 | rabbitmq {
6 | connectionfactory {
7 | username = 'guest'
8 | password = 'guest'
9 | hostname = 'localhost'
10 | }
11 | }
12 | {code}
13 |
14 | Those are settings which are necessary in order for the plugin to be able to connect to and communicate with a RabbitMQ server.
15 |
16 | Following is a list of other configuration settings supported by the plugin.
17 |
18 | {table}
19 | *Configuration Property* | *Description* | *Default*
20 | rabbitmq.connectionfactory.username | The user name for connection to the server | (none)
21 | rabbitmq.connectionfactory.password | The password for connection to the server | (none)
22 | rabbitmq.connectionfactory.hostname | The host name of the server | (none)
23 | rabbitmq.connectionfactory.virtualHost | The name of the virtual host to connect to | '/'
24 | rabbitmq.connectionfactory.channelCacheSize | The connection channel cache size | 10
25 | rabbitmq.concurrentConsumers | The number of concurrent consumers to create per message handler. Raising the number is recommended in order to scale the consumption of messages coming in from a queue. Note that ordering guarantees are lost when multiple consumers are registered. | 1
26 | rabbitmq.disableListening | Disables all service listeners so that they won't receive any messages. | false
27 | rabbitmq.retryPolicy.maxAttempts | Sets the maximum number of retries for failed message deliveries | 0
28 | {table}
29 |
--------------------------------------------------------------------------------
/src/docs/guide/configuration/advancedConfig.gdoc:
--------------------------------------------------------------------------------
1 | When you need fine-grained control over your service listeners, you can tap into the power of Spring. Since each service listener is implemented as a set of Spring beans, you can use Grails' [bean property override|http://grails.org/doc/latest/guide/spring.html#propertyOverrideConfiguration] mechanism to provide your own low-level settings.
2 |
3 | So how are these beans set up? If a service has either a @rabbitQueue@ or @rabbitSubscribe@ property, then you will have these beans:
4 |
5 | * @_MessageListenerContainer@ of type [SimpleMessageListenerContainer|api:org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer]
6 | * @RabbitAdapter@ of type [MessageListenerAdapter|api:org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter]
7 |
8 | As an example, let's say you have a @MessageStoreService@ like so:
9 |
10 | {code}
11 | class MessageStoreService {
12 | static rabbitSubscribe = [exchange: "amq.topic", routingKey: "logs.#"]
13 | ...
14 | }
15 | {code}
16 |
17 | You can then customise things like the number of concurrent consumers, whether the channel is transacted, what the prefetch count should be, and more! Simply add code like this to your runtime configuration (Config.groovy):
18 |
19 | {code}
20 | beans {
21 | messageStoreService_MessageListenerContainer {
22 | channelTransacted = false
23 | concurrentConsumers = 10
24 | prefetchCount = 5
25 | queueNames = ["q1", "q2"] as String[]
26 | }
27 |
28 | messageStoreServiceRabbitAdapter {
29 | encoding = "UTF-8"
30 | responseRoutingKey = "replyQueue"
31 | }
32 | }
33 | {code}
34 |
35 | This approach works for any property that accepts a basic type. But what about bean references? In this case, you can't use the bean property overrides. Fortunately, the most common bean reference you are likely to want to override, the message converter, has a dedicated configuration option:
36 |
37 | {code}
38 | rabbitmq.messageConverterBean = "myCustomMessageConverter"
39 | {code}
40 |
41 | This is a global setting that accepts the name of a message converter bean. For the rare occasions that you need to override other bean references, you can declare your own @_MessageListenerContainer@ or @_RabbitAdapter@ beans in resources.groovy.
42 |
43 | Finally, you can override some of the global config options on a per-service basis:
44 |
45 | {code}
46 | rabbitmq {
47 | services {
48 | messageStoreService {
49 | concurrentConsumers = 50
50 | disableListening = true
51 | }
52 | }
53 | }
54 | {code}
55 |
56 | There are many options for customisation and we hope the above will get you started.
57 |
--------------------------------------------------------------------------------
/src/docs/guide/configuration/configuringExchanges.gdoc:
--------------------------------------------------------------------------------
1 | Queues are the foundation of consuming messages, but what if you want to send messages? In AMQP, you send messages to an exchange and the exchange then routes those messages to the appropriate queues based on something called a binding. The key to setting up complex messaging systems lies in configuring these exchanges and queues appropriately.
2 |
3 | h3. Declaring an exchange
4 |
5 | Let's start with an example of how to set up a simple exchange (with no queues):
6 |
7 | {code}
8 | rabbitmq {
9 | connectionfactory {
10 | ...
11 | }
12 | queues = {
13 | exchange name: 'my.topic', type: topic
14 | }
15 | }
16 | {code}
17 |
18 | As you can probably guess, this will create a topic exchange with the name 'my.topic'. There are two things to note at this point:
19 |
20 | # the name and type are required
21 | # the type value is _not_ a string literal
22 |
23 | So what types are available to you?
24 |
25 | {table}
26 | *Type* | *Description*
27 | direct | An exchange that only routes messages that are bound to it with a key that matches the routing key of the message exactly. Typically this exchange is used for point-to-point messaging and the routing key is the queue name.
28 | fanout | Sends messages to all queues bound to it. It basically does a broadcast.
29 | topic | Similar to the @fanout@ exchange, this routes messages to the queues bound to it, but only queues whose binding matches a message's routing key will receive that message. Wildcards are supported in the binding.
30 | headers | Similar to topic, but messages can be filtered by other any message header, not just the routing key.
31 | {table}
32 |
33 | The exchange declaration also supports a couple of extra options that should be familiar from the queue declarations:
34 |
35 | {table}
36 | *Option* | *Description*
37 | autoDelete | If @true@, the exchange will be removed from the broker when there are no more queues bound to it. Note that this doesn't take effect until at least one queue is bound to the exchange.
38 | durable | If @true@, the exchange will survive a restart of the broker.
39 | {table}
40 |
41 | With the above syntax, it is up to you to bind queues to the exchange via another AMQP client or via the RabbitMQ management interface. In other words, this is most suitable if your Grails application is purely a publisher of messages and not a consumer (or at least not a consumer of 'my.topic' messages).
42 |
43 | What if you want to create queues and automatically bind them to the exchange? Don't worry, that's supported by the configuration DSL too.
44 |
45 | h3. Binding queues to exchanges
46 |
47 | An exchange on its own isn't particularly useful, but we can easily bind queues to it by declaring them as nested entries:
48 |
49 | {code}
50 | rabbitmq {
51 | connectionfactory {
52 | ...
53 | }
54 | queues = {
55 | exchange name: 'my.topic', type: topic, durable: false, {
56 | foo durable: true, binding: 'shares.#'
57 | bar durable: false, autoDelete: true, binding: 'shares.nyse.?'
58 | }
59 | }
60 | }
61 | {code}
62 |
63 | In the example above, we bind two queues ('foo' and 'bar') to the exchange 'my.topic'. Since this is a topic exchange, we can use a binding key to filter which messages go from 'my.topic' to each queue. So in this case, only messages with a routing key beginning with 'shares.' will end up on the 'foo' queue. 'bar' will only receive messages whose routing key begins with 'shares.nyse.'.
64 |
65 | This approach isn't limited to topic exchanges: you can automatically bind queues to any exchange type. There are a few things to bear in mind though:
66 |
67 | # the default binding for direct exchanges is the queue name (unless this is explicitly overridden by a 'binding' option);
68 | # the 'binding' is ignored for fanout exchanges; and
69 | # the headers exchange requires a map of message header names and values for its binding.
70 |
71 | {note}
72 | RabbitMQ has several built-in exchanges with names of the form 'amq.*', for example 'amq.direct'. If you want to bind to these, you currently have to declare them with the correct attributes, i.e.
73 |
74 | {code}
75 | exchange name: "amq.direct", type: direct, durable: true, autoDelete: false
76 | {code}
77 | {note}
78 |
79 | As you can imagine, these few building blocks allow you to configure some pretty complex messaging systems with very little effort. You can tailor the messaging system to your needs rather than tailor your applications to the messaging system.
80 |
81 |
82 |
--------------------------------------------------------------------------------
/src/docs/guide/configuration/configuringQueues.gdoc:
--------------------------------------------------------------------------------
1 | Queues must be declared in the RabbitMQ server before consumers can be associated with those queues and before messages may be sent to those queues. If the Grails application will be sending messages to or receiving messages from queues that may not already be declared in the RabbitMQ server, the application needs to declare those queues up front. One way to do that is to add beans to the Spring application context of type @org.springframework.amqp.core.Queue@. That
2 | might look something like this:
3 |
4 | {code}
5 | // grails-app/conf/spring/resources.groovy
6 | beans = {
7 | myQueue(org.springframework.amqp.core.Queue, 'myQueueName')
8 | myOtherQueue(org.springframework.amqp.core.Queue, 'myOtherQueueName') {
9 | autoDelete = false
10 | durable = true
11 | exclusive = false
12 | arguments = [arg1: 'val1', arg2: 'val2']
13 | }
14 | }
15 | {code}
16 |
17 | The plugin also supports a DSL for describing these queues. This DSL is expressed in @grails-app/conf/Config.groovy@. The code below configures the same queues as the previous code sample.
18 |
19 | {code}
20 | // grails-app/conf/Config.groovy
21 | rabbitmq {
22 | connectionfactory {
23 | username = 'guest'
24 | password = 'guest'
25 | hostname = 'localhost'
26 | }
27 | queues = {
28 | myQueueName()
29 | myOtherQueueName autoDelete: false, durable: true, exclusive: false, arguments: [arg1: 'val1', arg2: 'val2']
30 | }
31 | }
32 | {code}
33 |
34 | {note}
35 | With both techniques, the @autoDelete@, @durable@ and @exclusive@ attributes default to @false@ and the @arguments@ attribute defaults to null.
36 | {note}
37 |
38 | So what do those queue options mean?
39 |
40 | {table}
41 | *Option* | *Description*
42 | autoDelete | If @true@, the queue will be removed from the broker when there are no more clients attached to it. Note that this doesn't take effect until after at least one client connects to the queue.
43 | durable | If @true@, the queue will survive a restart of the broker.
44 | exclusive | Only the client that created the queue can connect to it.
45 | {table}
46 |
47 | One final thing: when you declare a standalone queue like this, it automatically gets bound to the broker's default exchange, which has an implicit name of '', i.e. the empty string. You can easily send messages to this queue via the [rabbitSend|allClasses] method.
48 |
--------------------------------------------------------------------------------
/src/docs/guide/consumingMessages.gdoc:
--------------------------------------------------------------------------------
1 | The plugin provides two simple ways of consuming messages:
2 |
3 | # from a named Queue
4 | # by subscribing to an exchange (the traditional pub/sub model)
5 |
6 | Which approach you take depends on whether you want to implement the pub/sub messaging model and how much control you need.
7 |
--------------------------------------------------------------------------------
/src/docs/guide/consumingMessages/manualQueueManagement.gdoc:
--------------------------------------------------------------------------------
1 | The plugin provides a convention based mechanism for associating a listener with a queue. Any Grails Service may express that it wants to receive messages on a specific queue by defining a static property named @rabbitQueue@ and
2 | assigning the property a string which represents the name of a queue.
3 |
4 | {code}
5 | package org.grails.rabbitmq.test
6 |
7 | class DemoService {
8 | static rabbitQueue = 'someQueueName'
9 |
10 | void handleMessage(message) {
11 | // handle message...
12 | }
13 | }
14 | {code}
15 |
16 | As with the pub/sub model, messages are delivered to the service by invoking the @handleMessage()@ method. That's all there is to it! The real trick is to configure your exchanges and queues with appropriate bindings, as we described in the configuration section.
17 |
18 | If you want more say in the configuration of the underlying listener, then you can also specify a map:
19 |
20 | {code}
21 | static rabbitQueue = [queues: "someQueueName", channelTransacted: true]
22 | {code}
23 |
24 | The "queues" option can either be a simple queue name or a list of queue names. Again, have a look at the [advanced configuration section|guide:advancedConfig] for information about the extra properties you can set here.
25 |
26 | One last subject to discuss is the form that the messages take.
27 |
--------------------------------------------------------------------------------
/src/docs/guide/consumingMessages/messages.gdoc:
--------------------------------------------------------------------------------
1 | What is a message? In the examples you've seen in this section, the message has been some arbitrary object but we haven't discussed what the type of that object might be. That's because, it can be pretty much anything! Within the messaging system, the content of a message is simply a byte array - it's up to the producer can consumer to interpret/convert that raw data.
2 |
3 | Fortunately the plugin (via [Spring AMQP|http://static.springsource.org/spring-amqp/docs/1.0.x/reference/html/#d0e335]) automatically handles messages whose content is in familiar forms, including:
4 |
5 | * strings
6 | * byte arrays
7 | * maps
8 | * other serializable types
9 |
10 | One manifestation of this support is that different message types may be handled with overloaded versions of @handleMessage()@:
11 |
12 | {code}
13 | package org.grails.rabbitmq.test
14 |
15 | class DemoService {
16 | static rabbitQueue = 'someQueueName'
17 |
18 | void handleMessage(String textMessage) {
19 | // handle String message...
20 | }
21 |
22 | void handleMessage(Map mapMessage) {
23 | // handle Map message...
24 | }
25 |
26 | void handleMessage(byte[] byteMessage) {
27 | // handle byte array message...
28 | }
29 | }
30 | {code}
31 |
32 | This is a great convenience, but be aware that using serializable Java objects limits the types of client you can interact with. If all the clients you're interested in are using Spring AMQP, then you should be fine, but don't expect Ruby or Python clients to handle @Map@ messages! For production systems, we recommend you use strings and byte arrays.
33 |
34 | Sometimes you want access to the raw message, particularly if you want to look at the message headers. If so, just change the signature of the @handleMessage()@ method and add an extra option to your @rabbitQueue@ or @rabbitSubscribe@ property:
35 |
36 | {code}
37 | package org.grails.rabbitmq.test
38 |
39 | import org.springframework.amqp.core.Message
40 |
41 | class DemoService {
42 | static rabbitQueue = [queues: 'someQueueName', messageConverterBean: '']
43 |
44 | void handleMessage(Message msg) {
45 | // Do something with the message headers
46 | println "Received message with content type ${msg.contentType};${msg.encoding}"
47 | ...
48 | }
49 | }
50 | {code}
51 |
52 | As you can see, all you have to do is accept an argument of type @Message@ and add the @messageConverterBean@ option with an empty string as its value. This disables the automatic message conversion, allowing you to interrogate the raw message as required.
53 |
--------------------------------------------------------------------------------
/src/docs/guide/consumingMessages/pubSub.gdoc:
--------------------------------------------------------------------------------
1 | One of the most common messaging models people use involves a producer broadcasting messages to all registered listeners (or more accurately, consumers). This is known as the publish/subscribe model, or pub/sub for short. There are two steps to getting this set up in Grails:
2 |
3 | # create the exchange you're going to publish messages to
4 | # create some consumers that subscribe to that exchange
5 |
6 | The first step can be done either outside of the Grails application or in the plugin's configuration. If the Grails application is the publisher, then it makes sense to declare the exchange in @grails-app/conf/Config.groovy@.
7 |
8 | The second step is dead easy with the plugin: create a service with a static @rabbitSubscribe@ property and a @handleMessage()@ method. Here's an example:
9 |
10 | {code}
11 | package org.example
12 |
13 | class SharesService {
14 | static rabbitSubscribe = 'shares'
15 |
16 | void handleMessage(message) {
17 | // handle message...
18 | }
19 | }
20 | {code}
21 |
22 | As long as the broker contains an exchange with the name @shares@, the @SharesService@ will receive all messages sent to that exchange. Every time a message is received from the broker, the service's @handleMessage()@ method is called with the message as its argument. We'll talk more about messages shortly.
23 |
24 | {note}
25 | The @rabbitSubscribe@ option only makes sense when applied to fanout and topic exchanges.
26 | {note}
27 |
28 | In the case of a topic exchange, you can filter messages based on the routing key. By default your service will receive all messages, but you can override this with an alternative syntax for @rabbitSubscribe@:
29 |
30 | {code}
31 | package org.example
32 |
33 | class SharesService {
34 | static rabbitSubscribe = [ name: 'shares', routingKey: 'NYSE.GE' ]
35 | ...
36 | }
37 | {code}
38 |
39 | In this example, the service will only receive messages that have a routing key of 'GE'. Of course, you can use standard AMQP wildcards too like 'NYSE.#', which will match all messages with a routing key that starts with 'NYSE.'.
40 |
41 | Under the hood, the plugin creates a temporary, exclusive queue for your service which is removed from the broker when your application shuts down. There is no way for you to control the name of the queue or attach another listener to it, but then that's the point in this case. If you do need more control, then you must manage the queues and their bindings yourself.
42 |
43 | The map syntax also allows you to customise the properties of the Spring message listener container and the corresponding listener adapter (see the section on [advanced configuration|guide:advancedConfig] for more details on these). For example,
44 |
45 | {code}
46 | static rabbitSubscribe = [
47 | name: 'shares',
48 | routingKey: 'NYSE.GE',
49 | encoding: "ISO-8859-1",
50 | prefetchCount: 1]
51 | {code}
52 |
53 | will set the encoding and prefetch count for just this service listener. This technique is also possible for straight queue listeners as well.
54 |
--------------------------------------------------------------------------------
/src/docs/guide/introduction.gdoc:
--------------------------------------------------------------------------------
1 | The RabbitMQ plugin provides integration with the RabbitMQ highly reliable enterprise messaging system. The
2 | plugin relies on [Spring AMQP|http://www.springsource.org/spring-amqp] as an implementation detail, which provides a high level abstraction
3 | for sending and receiving messages.
4 |
5 | This guide documents configuration details and usage details for the plugin. More information on
6 | RabbitMQ itself is available at [rabbitmq.com|http://www.rabbitmq.com/].
--------------------------------------------------------------------------------
/src/docs/guide/introduction/changeLog.gdoc:
--------------------------------------------------------------------------------
1 | h3. Version 0.3.2 - 16 Mar 2011
2 |
3 | * Upgrade to Spring AMQP 1.0.0.M3
4 |
5 | h3. Version 0.3.1 - 14 Feb 2011
6 |
7 | * spring-core dependency now excluded
8 | * Corrected the SCM and documentation URLs in the plugin descriptor
9 |
10 | h3. Version 0.3 - 7 Feb 2011
11 |
12 | * Upgraded to Spring AMQP 1.0.0 M2
13 | * Added transaction support
14 | * Added support for pub/sub model
15 | * Applications can now configure exchanges and bindings in addition to queues
16 | * Applications can now connect to any virtual host, not just '/'
17 | * Bug fixes:
18 | ** [GRAILSPLUGINS-2496|http://jira.codehaus.org/browse/GRAILSPLUGINS-2496] - Messages are now picked up when the application starts
19 |
--------------------------------------------------------------------------------
/src/docs/guide/links.yml:
--------------------------------------------------------------------------------
1 | introduction: 1. Introduction To The RabbitMQ Plugin
2 | changeLog: 1.1 Change log
3 | configuration: 2. Configuration
4 | configuringQueues: 2.1 Configuring Queues
5 | configuringExchanges: 2.2 Configuring Exchanges
6 | sendingMessages: 3. Sending Messages
7 | consumingMessages: 4. Consuming Messages
8 | pubSub: 4.1 Pub-Sub
9 | manualQueueManagement: 4.2 Manual queue management
10 | messages: 4.3 Messages
11 | usingTheRabbitTemplateDirectly: 5. Using The RabbitTemplate Directly
12 |
--------------------------------------------------------------------------------
/src/docs/guide/rabbitTemplate.gdoc:
--------------------------------------------------------------------------------
1 | Most of the interaction with the RabbitMQ server is being handled by an instance of [RabbitTemplate|api:org.springframework.amqp.rabbit.core.RabbitTemplate]. For many applications this is happening at a lower level than the application needs to be concerned with. The plugin does provide a Spring bean to the application context that is an instance of the @RabbitTemplate@ class which may be used directly. The bean name is @rabbitTemplate@.
2 |
3 | {code}
4 | class MessageController {
5 |
6 | def rabbitTemplate
7 |
8 | def sendMessage = {
9 | rabbitTemplate.convertAndSend('someQueueName', 'someMessage)
10 | ...
11 | }
12 | }
13 | {code}
14 |
--------------------------------------------------------------------------------
/src/docs/guide/rewriteRules.txt:
--------------------------------------------------------------------------------
1 | 1.%20Introduction%20To%20The%20RabbitMQ%20Plugin.html -> introductionToTheRabbitMQPlugin.html
2 | 2.%20Configuration.html -> configuration.html
3 | 3.%20Sending%20Messages.html -> sendingMessages.html
4 | 4.%20Consuming%20Messages.html -> consumingMessages.html
5 | 5.%20Using%20The%20RabbitTemplate%20Directly.html -> usingTheRabbitTemplateDirectly.html
6 |
--------------------------------------------------------------------------------
/src/docs/guide/sendingMessages.gdoc:
--------------------------------------------------------------------------------
1 | The plugin adds a method named @rabbitSend@ to all Grails artefacts (Controllers, Services, TagLibs, etc...). The @rabbitSend@ method accepts 2 parameters. The first parameter is a queue name and the second parameter is the message being sent.
2 |
3 | {code}
4 | class MessageController {
5 |
6 | def sendMessage = {
7 | rabbitSend 'someQueueName', 'someMessage'
8 | ...
9 | }
10 | }
11 | {code}
12 |
13 | Messages may also be sent by interacting with the @RabbitTemplate@ Spring bean directly. See the [Using The RabbitTemplate Directly|guide:rabbitTemplate] section for more information.
14 |
--------------------------------------------------------------------------------
/src/docs/guide/toc.yml:
--------------------------------------------------------------------------------
1 | introduction:
2 | title: Introduction To The RabbitMQ Plugin
3 | changeLog: Change log
4 | configuration:
5 | title: Configuration
6 | configuringQueues: Configuring Queues
7 | configuringExchanges: Configuring Exchanges
8 | advancedConfig: Advanced Configuration
9 | sendingMessages: Sending Messages
10 | consumingMessages:
11 | title: Consuming Messages
12 | pubSub: Pub-Sub
13 | manualQueueManagement: Manual queue management
14 | messages: Messages
15 | rabbitTemplate: Using The RabbitTemplate Directly
16 |
--------------------------------------------------------------------------------
/src/docs/ref/All Classes/rabbitSend.gdoc:
--------------------------------------------------------------------------------
1 | h1. rabbitSend
2 |
3 | h2. Purpose
4 |
5 | Sends a message to a RabbitMQ broker.
6 |
7 | h2. Examples
8 |
9 | {code}
10 | // Send a string message to the default direct exchange. It will be routed to any
11 | // queues that are bound to the default exchange with the key '' (an empty string).
12 | rabbitSend "Some message"
13 |
14 | // Send a map message to the default direct exchange. The message will be routed to
15 | // the queue with the name 'myQueue'.
16 | rabbitSend "myQueue", [cmd: "addBook", title: "The Shining", author: "Stephen King"]
17 |
18 | // Send a string message to a 'prices' exchange with a routing key of 'shares.NYSE.GE'.
19 | rabbitSend "prices", "shares.NYSE.GE", "$354.23"
20 | {code}
21 |
22 | h2. Description
23 |
24 | The @rabbitSend()@ method is basically a convenience over the [Spring AMQP convertAndSend()|http://static.springsource.org/spring-amqp/docs/1.0.x/reference/html/#d0e462] method. It has three basic forms:
25 |
26 | {code}
27 | rabbitSend message
28 | rabbitSend routingKey, message
29 | rabbitSend exchangeName, routingKey, message
30 | {code}
31 |
32 | If @routingKey@ is left out, it defaults to a value of '', i.e. the empty string. The same goes for @exchangeName@, in which case the message is routed to the queue with the same name as the routing key (if specified).
33 |
34 | The message can be any serializable type, although if you want to interoperate with non-Java clients, it's best to stick to string and byte array messages.
35 |
36 | For complex requirements, you can even pass in an object that processes the message after construction. See the Spring AMQP guide for more information on that.
37 |
--------------------------------------------------------------------------------
/src/main/groovy/grails.plugins.rabbitmq/AutoQueueMessageListenerContainer.groovy:
--------------------------------------------------------------------------------
1 | package grails.plugins.rabbitmq
2 |
3 | import org.slf4j.LoggerFactory
4 | import org.springframework.amqp.core.BindingBuilder
5 | import org.springframework.amqp.core.DirectExchange
6 | import org.springframework.amqp.core.FanoutExchange
7 | import org.springframework.amqp.core.TopicExchange
8 | import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer
9 | import org.springframework.context.ApplicationContext
10 | import org.springframework.context.ApplicationContextAware
11 |
12 | /**
13 | * Message listener container that creates a temporary, auto-delete queue and
14 | * binds it to a configured exchange.
15 | */
16 | class AutoQueueMessageListenerContainer extends SimpleMessageListenerContainer implements ApplicationContextAware {
17 | private static final log = LoggerFactory.getLogger(AutoQueueMessageListenerContainer)
18 |
19 | String rabbitAdminBeanName = "adm"
20 | ApplicationContext applicationContext
21 |
22 | /**
23 | * The exchange to bind the temporary queue to. This can be a string
24 | * containing the name of the exchange, or a map containing the name
25 | * of the exchange (key: 'name') and the routing key (key: 'routing').
26 | * If no routing key is specified, the match-all wildcard ('#') is used.
27 | */
28 | String exchangeBeanName
29 |
30 | /**
31 | * The routing key to bind the queue to the exchange with. This is
32 | * the 'match-all' wildcard by default: '#'.
33 | */
34 | String routingKey = '#'
35 |
36 | protected void doStart() {
37 | // Check the exchange name has been specified.
38 | if (!exchangeBeanName) {
39 | log.error "Property [exchangeBeanName] must have a value!"
40 | return
41 | }
42 |
43 | // First, create a broker-named, temporary queue.
44 | def adminBean = getApplicationContext().getBean(rabbitAdminBeanName)
45 | def queue = adminBean.declareQueue()
46 |
47 | // Now bind this queue to the named exchanged. If the exchange is a
48 | // fanout, then we don't bind with a routing key. If it's a topic,
49 | // we use the 'match-all' wildcard. Other exchange types are not
50 | // supported.
51 | def exchange = getApplicationContext().getBean(exchangeBeanName)
52 |
53 | def binding = null
54 | if (exchange instanceof FanoutExchange) {
55 | binding = BindingBuilder.bind(queue).to(exchange);
56 | }
57 | else if (exchange instanceof DirectExchange || exchange instanceof TopicExchange) {
58 | binding = BindingBuilder.bind(queue).to(exchange).with(routingKey);
59 | }
60 | else {
61 | log.error "Cannot subscribe to an exchange ('${exchange.name}') that is neither a fanout nor a topic"
62 | return
63 | }
64 |
65 | adminBean.declareBinding(binding)
66 |
67 | // Let the super class do the rest.
68 | super.setQueueNames(queue.name)
69 | super.doStart()
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/groovy/grails.plugins.rabbitmq/RabbitConfigurationHolder.groovy:
--------------------------------------------------------------------------------
1 | package grails.plugins.rabbitmq
2 |
3 | class RabbitConfigurationHolder {
4 |
5 | def rabbitmqConfig
6 |
7 | public RabbitConfigurationHolder(rabbitmqConfig) {
8 | this.rabbitmqConfig = rabbitmqConfig
9 | }
10 |
11 | int getDefaultConcurrentConsumers() {
12 | return rabbitmqConfig.concurrentConsumers ?: 1
13 | }
14 |
15 | int getServiceConcurrentConsumers(def service) {
16 | def propertyName = service.propertyName
17 | return rabbitmqConfig.services?."${propertyName}"?.concurrentConsumers ?: defaultConcurrentConsumers
18 | }
19 |
20 | boolean isListeningDisabled() {
21 | return rabbitmqConfig.disableListening
22 | }
23 |
24 | boolean isServiceEnabled(def service) {
25 | if (listeningDisabled) return false
26 | def propertyName = service.propertyName
27 | return !rabbitmqConfig.services?."${propertyName}"?.disableListening
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/groovy/grails.plugins.rabbitmq/RabbitDynamicMethods.groovy:
--------------------------------------------------------------------------------
1 | package grails.plugins.rabbitmq
2 |
3 | import org.springframework.amqp.core.Address
4 | import org.springframework.amqp.core.Message
5 | import org.springframework.amqp.core.MessagePostProcessor
6 |
7 | /**
8 | * Class for applying the dynamic rabbitSend() and rabbitRpcSend() methods to
9 | * specified classes. Makes unit testing and reuse easier.
10 | */
11 | class RabbitDynamicMethods {
12 |
13 | static void applyAllMethods(target, ctx) {
14 | applyRabbitSend(target, ctx)
15 | // applyRabbitRpcSend(target, ctx)
16 | }
17 |
18 | static void applyRabbitSend(target, ctx) {
19 | target.metaClass.rabbitSend = { Object[] args ->
20 | // The last argument of convertAndSend is of type Object so the
21 | // automatic conversion of GString to String doesn't happen as
22 | // it does for the other arguments. Since the code in that method
23 | // checks for String, we do the conversion manually.
24 | args = processArgs(args)
25 | ctx.rabbitTemplate.convertAndSend(*args)
26 | }
27 | }
28 |
29 | static void applyRabbitRpcSend(target, ctx) {
30 | target.metaClass.rabbitRpcSend = { Object[] args ->
31 | // Last argument is a reply queue name
32 | // TODO add support for a closure or a service listener as an alternative
33 | // to the reply queue name. In those cases, the reply queue should automatically
34 | // be created and the closure/listener invoked when the reply is received.
35 | def newArgs = args.toList()
36 | def reply = newArgs.pop()
37 | newArgs = processArgs(newArgs)
38 |
39 | newArgs << ({ Message msg ->
40 | msg.messageProperties.replyTo = new Address(reply)
41 | return msg
42 | } as MessagePostProcessor)
43 |
44 | ctx.rabbitTemplate.convertAndSend(newArgs)
45 | }
46 | }
47 |
48 | private static processArgs(args) {
49 | int i = args[-1] instanceof MessagePostProcessor ? -2 : -1
50 | if (args[i] instanceof GString) {
51 | args[i] = args[i].toString()
52 | }
53 | return args
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/groovy/grails.plugins.rabbitmq/RabbitErrorHandler.groovy:
--------------------------------------------------------------------------------
1 | package grails.plugins.rabbitmq
2 |
3 | import org.slf4j.Logger
4 | import org.slf4j.LoggerFactory
5 | import org.springframework.util.ErrorHandler
6 |
7 | /**
8 | * A simple error handler that logs exceptions via SLF4J.
9 | */
10 | class RabbitErrorHandler implements ErrorHandler {
11 | private static final Logger log = LoggerFactory.getLogger(this)
12 |
13 | void handleError(Throwable t) {
14 | log.error "Rabbit service listener failed.", t
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/groovy/grails.plugins.rabbitmq/RabbitQueueBuilder.groovy:
--------------------------------------------------------------------------------
1 | package grails.plugins.rabbitmq
2 |
3 | import org.springframework.amqp.core.*
4 | import org.slf4j.LoggerFactory
5 |
6 | class RabbitQueueBuilder {
7 |
8 | private final static log = LoggerFactory.getLogger(RabbitQueueBuilder)
9 |
10 | List bindings = []
11 | List exchanges = []
12 | List queues = []
13 |
14 | private currentExchange
15 |
16 | def methodMissing(String methodName, args) {
17 | Queue queue
18 |
19 | def argsMap = args ? args[0] : [:]
20 | if(argsMap) {
21 | Boolean autoDelete = Boolean.valueOf(argsMap.autoDelete)
22 | Boolean exclusive = Boolean.valueOf(argsMap.exclusive)
23 | Boolean durable = Boolean.valueOf(argsMap.durable)
24 | Map arguments
25 | if(argsMap.arguments instanceof Map) {
26 | arguments = argsMap.arguments
27 | }
28 | queue = new Queue(methodName, durable, exclusive, autoDelete, arguments)
29 | } else {
30 | queue = new Queue(methodName)
31 | }
32 |
33 | // If we are nested inside of an exchange definition, create
34 | // a binding between the queue and the exchange.
35 | if (currentExchange) {
36 | def newBinding = [ queue: methodName, exchange: currentExchange.name ]
37 | bindings << newBinding
38 |
39 | switch (currentExchange.type) {
40 | case DirectExchange:
41 | if (argsMap.binding && !(argsMap.binding instanceof CharSequence)) {
42 | throw new RuntimeException(
43 | "The binding for queue '${methodName}' to direct " +
44 | "exchange '${currentExchange.name}' must be a string.")
45 | }
46 |
47 | // Use the name of the queue as a default binding if no
48 | // explicit one is declared.
49 | newBinding.rule = argsMap.binding ?: queue.name
50 | break
51 |
52 | case FanoutExchange:
53 | // Any binding will be ignored.
54 | log.warn "'${currentExchange.name}' is a fanout exchange - binding for queue '${methodName}' ignored"
55 | newBinding.rule = "" // rabbit client API doesn't like a null binding
56 | break
57 |
58 | case HeadersExchange:
59 | if (!(argsMap.binding instanceof Map)) {
60 | throw new RuntimeException(
61 | "The binding for queue '${methodName}' to headers " +
62 | "exchange '${currentExchange.name}' must be declared " +
63 | "and must be a map.")
64 | }
65 |
66 | newBinding.rule = argsMap.binding
67 | break
68 |
69 | case TopicExchange:
70 | if (!(argsMap.binding instanceof CharSequence)) {
71 | throw new RuntimeException(
72 | "The binding for queue '${methodName}' to topic " +
73 | "exchange '${currentExchange.name}' must be declared " +
74 | "and must be a string.")
75 | }
76 |
77 | newBinding.rule = argsMap.binding
78 | break
79 | }
80 | }
81 | queues << queue
82 | }
83 |
84 | /**
85 | * Defines a new exchange.
86 | * @param args The properties of the exchange, such as its name
87 | * and whether it is durable or not.
88 | * @param c An optional closure that includes queue definitions.
89 | * If provided, the queues are bound to this exchange.
90 | */
91 | def exchange(Map args, Closure c = null) {
92 | if (currentExchange) throw new RuntimeException("Cannot declare an exchange within another exchange")
93 | if (!args.name) throw new RuntimeException("A name must be provided for the exchange")
94 | if (!args.type) throw new RuntimeException("A type must be provided for the exchange '${args.name}'")
95 | exchanges << [ *:args ]
96 |
97 | if (c) {
98 | currentExchange = exchanges[-1]
99 | c = c.clone()
100 | c.delegate = this
101 | c()
102 | }
103 |
104 | // Clear the current exchange regardless of whether there was
105 | // a closure argument or not. Just an extra safety measure.
106 | currentExchange = null
107 | }
108 |
109 | def getDirect() { return DirectExchange }
110 | def getFanout() { return FanoutExchange }
111 | def getHeaders() { return HeadersExchange }
112 | def getTopic() { return TopicExchange }
113 | }
114 |
--------------------------------------------------------------------------------
/src/main/groovy/grails.plugins.rabbitmq/RabbitServiceConfigurer.groovy:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2012 the original author or authors
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package grails.plugins.rabbitmq
17 |
18 | import grails.util.GrailsClassUtils as GCU
19 | import org.slf4j.LoggerFactory
20 | import org.springframework.amqp.core.AcknowledgeMode
21 |
22 | import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer
23 | import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter
24 |
25 | /**
26 | *
Configures the Spring beans required to set up a service as an AMQP
27 | * listener. The service must have either a static rabbitQueue
28 | * property declared or a static rabbitSubscribe one (but not
29 | * both). If neither of these exist, nothing is configured. Otherwise,
30 | * it will configure a {@link SimpleMessageListenerContainer} and an
31 | * associated {@link MessageListenerAdapter}.