49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/src/en/migrateToTheNewCentralRepository.gdoc:
--------------------------------------------------------------------------------
1 | h1. How to migrate to the new Grails Central repository
2 |
3 | In March 2012 Grails migrated from a custom SVN based repository for plugins, to one based on Artifactory. The benefits of doing so are as follows:
4 |
5 | * Publishing control - Each plugin developer can only publish the plugins they are responsible for
6 | * Maven compatibility - Maven, Gradle and other build tools can more easily resolve plugins
7 | * Performance - Resolves speeds can be made to increase by providing better metadata
8 |
9 | This HOWTO is for plugin developers who would like to know the steps necessary to move to the new plugin repository.
10 |
11 | h2. First Steps
12 |
13 | In order to publish to the new repository you need to first submit your plugin for approval through the [plugin portal|http://grails.org/plugins/submitPlugin]. Once you have been notified of the approval, you are ready to publish.
14 |
15 | h2. Moving your code to another hosting provider
16 |
17 | Since the old SVN repository will be read-only we encourage folks to move their plugins to alternative hosting providers. Github is a great option, see the details describing how to [create a repo|http://help.github.com/create-a-repo/]
18 |
19 | h2. Upgrading the Release plugin
20 |
21 | Next you need to make sure you are using 2.0.0 or above of the [Release plugin|http://grails.org/plugin/release] to publish plugins.
22 |
23 | {warning}
24 | The old @release-plugin@ command that ships with the Grails 1.x line will no longer work! You must use the new release plugin.
25 | {warning}
26 |
27 | This can be achieved by adding the Grails central repository to your BuildConfig.groovy respositories:
28 |
29 | {code}
30 | grailsRepo "http://grails.org/plugins"
31 | {code}
32 |
33 | And then running install-plugin:
34 |
35 | {code}
36 | grails install-plugin release 2.0.0
37 | {code}
38 |
39 | or add it as a build dependency in @grails-app/conf/BuildConfig.groovy@:
40 |
41 | {code}
42 | grails.project.dependency.resolution = {
43 | ...
44 | plugins {
45 | build "\:release\:2.0.0", {
46 | export = false
47 | }
48 | ...
49 | }
50 | }
51 | {code}
52 |
53 | h2. Configuration
54 |
55 | In order to publish to the central repository you need to configure your grails.org credentials in @~/.grails/settings.groovy@ as follows:
56 |
57 | {code}
58 | grails.project.repos.grailsCentral.username='YOUR USERNAME'
59 | grails.project.repos.grailsCentral.password='YOUR PASSWORD'
60 | {code}
61 |
62 | h2. Publishing
63 |
64 | To publish a plugin simply run @publish-plugin@ command as usual:
65 |
66 | {code}
67 | grails publish-plugin
68 | {code}
69 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Grails HOWTOs
2 | =============
3 |
4 | Grails is a modern rapid web application development framework for the JVM. It has its [own user guide] (http://grails.org/doc/latest/) that contains lots of reference material. This project _does not_ replace that. Instead, it complements the user guide by providing standalone documents that explain how to do one thing. The idea is that these HOWTO guides will be created and maintained by the community.
5 |
6 | If you would like to contribute, simply send an internal GitHub message to 'pledbrook' requesting commit access. Once granted access, you will be able to directly commit to this repository.
7 |
8 | Building
9 | --------
10 |
11 | Once you have cloned the repository locally, all you have to do is run
12 |
13 | ./gradlew docs
14 |
15 | from the root of the project. This will generate all the HOWTO guides in all the languages inside the `build/docs` directory. If you would like to generate the guides only for a particular language, simply add the language suffix. For example,
16 |
17 | ./gradlew docs_fr
18 |
19 | will generate the French HOWTO guides but no others.
20 |
21 | Creating a HOWTO
22 | ----------------
23 |
24 | All the guides are standalone gdoc files that reside under the `src/$lang` directories. To add a standard English guide, simply put it in the `src/en` directory.
25 |
26 | The only requirements of the source file are that the first line is an `h1.` heading, which becomes the title of the HOWTO, and `h2.` is used for the top-level sections. Links between HOWTOs are not supported at this moment in time.
27 |
28 | As soon as you create the gdoc file, it will be processed automatically by the build. The resulting HTML file has the same base name as the gdoc file.
29 |
30 | Community
31 | ---------
32 |
33 | This will be an open repository allowing anyone who's interested to contribute. On the flip side, there is no central editorial control, so contributors are expected to police the system themselves to prevent abuse.
34 |
35 | Customising the styling
36 | -----------------------
37 |
38 | The HTML layout for the HOWTO guides is defined in the file `resources/templates/how-to-template.html`. Static resources required by the template, such as images and stylesheets, should be placed in the respective directory under `resources/images`, `resources/css` and `resources/js` as appropriate.
39 |
40 | When adding links to static resources inside the template, be sure to use the `resourcesPath` variable like so:
41 |
42 |
43 |
44 | This ensures that the template works regardless of whether the generated guide is in a language-specific directory or not.
45 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/src/en/contributeToTheseGuides.gdoc:
--------------------------------------------------------------------------------
1 | h1. Contribute to these guides
2 |
3 | These HOWTO guides are built from a source project hosted on GitHub that anyone is free to contribute to. Contributions can take the form of modifications to existing guides, the addition of new ones, or changes to the styling of the published HOWTOs.
4 |
5 | If you would like to contribute, simply send an _internal_ GitHub message to 'pledbrook' requesting commit access. It's not obvious how to do this in GitHub, but basically you click the Compose Message link on your inbox/notifications page:
6 |
7 | !contributeToTheseGuides/compose_link.png!
8 |
9 | and then add the 'pledbrook' handle to the recipient field:
10 |
11 | !contributeToTheseGuides/message.png!
12 |
13 | Once access has been granted, you will be able to commit directly to the "project repository":https://github.com/grails/grails-howtos .
14 |
15 | h2. Building the guides
16 |
17 | Once you have cloned the repository locally, all you have to do is run
18 |
19 | bc.
20 | ./gradlew docs
21 |
22 | from the root of the project. This will generate all the HOWTO guides in all the languages inside the @build/docs@ directory. If you would like to generate only the guides for a particular language, simply add the language suffix. For example,
23 |
24 | bc.
25 | ./gradlew docs_fr
26 |
27 | will generate the French HOWTO guides but no others.
28 |
29 | h2. Creating a HOWTO
30 |
31 | All the guides are standalone gdoc files that reside under the @src/$lang@ directories. So, to add a 'Deploy to JBoss' English HOWTO, you would simply create the file 'src/en/deployToJboss.gdoc' and add the HOWTO content to it.
32 |
33 | The only requirements for each HOWTO gdoc file are that:
34 |
35 | # the first line is an @h1.@ heading, which becomes the title of the HOWTO; and
36 | # @h2.@ is used for the top-level sections.
37 |
38 | For example, a very basic gdoc would look like:
39 |
40 | {code}
41 | \h1. Deploy to JBoss
42 |
43 | Introduction to this guide
44 |
45 | \h2. The basics
46 |
47 | ...
48 | {code}
49 |
50 | Links between HOWTOs are not supported at this moment in time, but external links are the same as for [standard gdoc syntax|http://grails.org/WikiSyntax].
51 |
52 | As soon as you create the gdoc file, it will be picked up automatically by the build the next time you run the @docs@ task. The resulting HTML file will have the same base name as the gdoc file, for example 'deployToJboss.html'.
53 |
54 | If you wish to add an image to a HOWTO, place the file in the 'resources/img' directory and insert an entry like \!\! into the gdoc source. For example, if you have the image 'resources/img/deployToJboss/deployCycle.png' then link to it using the syntax:
55 |
56 | bc.
57 | \!deployToJboss/deployCycle.png\!
58 |
59 | Note that the path specified inside the exclamation marks is relative to the 'resources/img' directory.
60 |
61 | h2. Customising the styling
62 |
63 | The HTML layout for the HOWTO guides is defined in the file 'resources/templates/how-to-template.html'. Static resources required by the template, such as images and stylesheets, should be placed in the respective directory under 'resources/img', 'resources/css' and 'resources/js' as appropriate.
64 |
65 | When adding links to static resources inside the template, be sure to use the @resourcesPath@ variable like so:
66 |
67 | {code:xml}
68 |
69 | {code}
70 |
71 | This ensures that the template works regardless of whether the generated guide is in a language-specific directory or not.
72 |
73 | h2. Community
74 |
75 | This is an open repository allowing anyone who's interested to contribute. On the flip side, there is no central editorial control, so contributors are expected to police the system themselves to prevent abuse.
76 |
--------------------------------------------------------------------------------
/src/fr/contribuerAuxGuides.gdoc:
--------------------------------------------------------------------------------
1 | h1. Contribuer aux guides
2 |
3 | Ces guides sont générés à partir du code source hébergé et partagé sur GitHub. Ses contributions peuvent prendre la forme d'une modification ou de l'ajout de nouvelles pages ou encore de la modification du style de ces guides.
4 |
5 | Pour contribuer, envoyez simplement un message _interne_ via GitHub à 'pledbrook' pour lui demander l'accès au commit. Ce n'est pas très clair comment faire dans GitHub, il faut cliquer sur le lien 'Compose Message' dans votre boîte de réception (inbox/notifications) :
6 |
7 | !contributeToTheseGuides/compose_link.png!
8 |
9 | Ensuite, ajoutez 'pledbrook' comme récipiendaire:
10 |
11 | !contributeToTheseGuides/message.png!
12 |
13 | Peter Ledbrooke ne parle pas français (ou le parle-t-il ?), envoyez lui le message anglais suivant : "Please add to grails-howtos project".
14 |
15 | Une fois que vous avez l'accès, vous pourrez commiter directement sur le "code source du projet":https://github.com/grails/grails-howtos
16 |
17 | h2. Générer le guide
18 |
19 | Une fois que vous avez cloné le projet localement, lancez cette commande :
20 |
21 | bc.
22 | ./gradlew docs
23 |
24 | dans le répertoire racine du projet. Cela va générer les pages HOWTOs de ce guide dans chacune des langues du répertoire @build/docs@. Pour générer le guide pour une langue spécifique, ajoutez la langue en suffix comme ceci
25 |
26 | bc.
27 | ./gradlew docs_fr
28 |
29 | Cette commande va générer le guide en français seulement.
30 |
31 | h2. Ajouter un HOWTO
32 |
33 | Tous les HOWTOs sont des pages autonomes dans le répertoire @src/$lang@. Pour ajouter le howto français 'Déployer sur JBoss', il vous faut donc créer le fichier 'src/deployerSurJboss.gdoc' et y ajouter le son contenu.
34 |
35 | Voici les seules exigences des fichiers gdoc :
36 |
37 | # La première ligne doit être un titre @h1.@, qui deviendra le titre du HOWTO; et
38 | # @h2.@ sera utilisé pour les sous-titres.
39 |
40 | Voici à quoi ressemble un gdoc :
41 |
42 | {code}
43 | \h1. Déployer sur JBoss
44 |
45 | Introduction au guide
46 |
47 | \h2. Avant de commencer
48 |
49 | ...
50 | {code}
51 |
52 | Les liens entre les HOWTOs ne sont pas supportés pour l'instant, par contre la syntaxedes liens externes est la même que dans la [syntaxe standard de gdoc|http://grails.org/WikiSyntax]
53 |
54 | Une fois que vous aurez créé votre fichier gdoc, il sera automatiquement généré la prochaine vous que lancerez la commande @docs@. Le fichier HTML résultant aura le même nom que votre fichier gdoc, example : 'deployerSurJboss.html'.
55 |
56 | Si vous souhaitez ajouter une image à un HOWTO, placez le fichier dans le répertoire 'resources/img' et ajoutez le code \!\! dans le code source de votre gdoc. Par exemple, si vous avez l'image 'resources/img/deployerSurJboss/cycle.png' alors le lien de l'image sera :
57 |
58 | bc.
59 | \!deployerSurJBoss/cycle.png\!
60 |
61 | NB: Le chemin entre les points exclamations est relatif au répertoire 'resources/img'.
62 |
63 | h2. Modifier le style
64 |
65 | La mise en forme HTML utilisé pour ce guide est défini dans le fichier 'resources/templates/how-to-template.html'. Les fichiers statiques requis pour le template, comme les images et le style css, devront être placés dans leur répertoire respectif soit 'resources/img', 'resources/css' et 'resources/js'.
66 |
67 | Lorsque vous ajoutez un lien à une ressource statique dans le template, assurez vous d'utiliser la variable @resourcesPath@ comme ceci :
68 |
69 | {code:xml}
70 |
71 | {code}
72 |
73 | De cette façon, le template fonctionnera peu importe si le guide généré pour pour une langue en particulier ou non.
74 |
75 | h2. Communauté
76 |
77 | Il s'agit d'un projet ouvert qui permet à tout le monde intéressé de contribuer. Par contre, il n'y a aucun contrôle éditoriale. On attend des contributeurs qu'ils autorégulent le système eux-même afin de prévenir les abus.
78 |
--------------------------------------------------------------------------------
/src/es/contribuirEstasGuias.gdoc:
--------------------------------------------------------------------------------
1 | h1. Contribuir a estas guías
2 |
3 | Estas guías HOWTO se construyen desde un proyecto alojado en GitHub al que cualquiera puede contribuir. Las contribuciones pueden ser modificaciones de las guías existentes, la adición de otras nuevas, o cambios en el estilo de los HOWTOs publicados.
4 |
5 | Si quieres contribuir, envía un mensaje interno de GitHub a 'pledbrook' solicitando acceso de commit. No es evidente cómo hacer esto en GitHub, pero, básicamente, hay que hacer clic en el enlace "Compose Message" en su página de notificaciones:
6 |
7 | !contributeToTheseGuides/compose_link.png!
8 |
9 | y luego añadir 'pledbrook' en el campo de destinatario:
10 |
11 | !contributeToTheseGuides/message.png!
12 |
13 | Una vez que se le haya concedido el acceso, serás capaz de hacer commit directamente en el repositorio del proyecto: https://github.com/grails/grails-howtos.
14 |
15 | h2. La construcción de las guías
16 |
17 | Una vez que has clonado el repositorios a nivel local, todo lo que tienes que hacer es ejecutar
18 |
19 | bc.
20 | ./gradlew docs
21 |
22 | en la raíz del proyecto. Esto va a generar todas las guías HOWTO en todas las lenguas dentro del directorio @build/docs@. Si quieres generar sólo las guías para un idioma en particular, sólo tiene que añadir el sufijo idioma. Por ejemplo,
23 |
24 | bc.
25 | ./gradlew docs_fr
26 |
27 | va a generar las guías HOWTO en frances, pero no las demás.
28 |
29 | h2. Creación de un HOWTO
30 |
31 | Todos los guías son independientes de los archivos gdoc que residen en el directorio @src/$lang@. Por lo tanto, para agregar un HOWTO "Desplegar en JBoss en Español", simplemente crea el archivo 'src/es/desplegarEnJboss.gdoc' y añade el contenido HOWTO a ella.
32 |
33 | Los únicos requisitos para cada archivo gdoc son las siguientes:
34 |
35 | # La primera línea es una cabecera @h1.@, que se convierte en el título del HOWTO; y
36 | # @h2.@ se utiliza para las secciones de nivel superior.
37 |
38 | Por ejemplo, un gdoc muy básico sería así:
39 |
40 | {code}
41 | \h1. Desplegar en JBoss
42 |
43 | Introducción a esta guía
44 |
45 | \h2. Conceptos básicos
46 |
47 | ...
48 | {code}
49 |
50 | Los enlaces entre HOWTOs no están soportados, pero los enlaces externos se ponen igual que con la [sintaxis gdoc estandar|http://grails.org/WikiSyntax].
51 |
52 | Tan pronto como se crea el archivo gdoc, será introducido en la documentación en la construcción la próxima vez que ejecute la tarea de @docs@. El archivo HTML resultante tendrá el mismo nombre que el archivo gdoc, por ejemplo 'desplegarEnJboss.html'.
53 |
54 | Si desea agregar una imagen a un HOWTO, coloque el archivo en el directorio "resources/img 'e inserte una entrada como \! \! en el fuente del gdoc. Por ejemplo, si tienes la imagen "resources/img/desplegarEnJboss/cicloDeDespliege.png"" puedes enlazar a ella usando esta sintaxis:
55 |
56 | bc.
57 | \!DeployToJboss/deployCycle.png\!
58 |
59 | Ten en cuenta que la ruta especificada dentro de los signos de exclamación es relativa al directorio 'resources/img'.
60 |
61 | h2. Personalizar el estilo
62 |
63 | El diseño HTML para la guía HOWTO se define en el archivo 'resources/templates/how-to-template.html'. Los recursos estáticos requeridos por la plantilla, como imágenes y hojas de estilo, se debe colocar en el directorio correspondiente bajo 'resources/img', 'resources/css' y 'resources/js' según proceda.
64 |
65 | Al añadir enlaces a recursos estáticos dentro de la plantilla, asegúrate de utilizar la variable @resourcesPath@ así:
66 |
67 | {code:xml}
68 |
69 | {code}
70 |
71 | Esto asegura que la plantilla funciona independientemente de si la guía está generada en un directorio específico para el lenguaje o no.
72 |
73 | h2. Comunidad
74 |
75 | Esto es un repositorio abierto que permite a cualquiera que esté interesado contribuir. Por otro lado, no existe un control editorial central, por lo se espera que los contribuyentes controlen ellos mismos el sistema para evitar abusos.
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/resources/css/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | text-align: center;
4 | font-size: 100%;
5 | line-height: 1.125em;
6 | font-family: 'Lucida Sans Unicode', 'Lucida Grande', 'Arial', sans-serif;
7 | }
8 |
9 | #header-container {
10 | width: 100%;
11 | min-width: 960px;
12 | height: 80px;
13 | background: rgb(117,163,25); /* Old browsers */
14 | background: -moz-linear-gradient(top, rgba(117,163,25,1) 0%, rgba(163,194,102,1) 100%); /* FF3.6+ */
15 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(117,163,25,1)), color-stop(100%,rgba(163,194,102,1))); /* Chrome,Safari4+ */
16 | background: -webkit-linear-gradient(top, rgba(117,163,25,1) 0%,rgba(163,194,102,1) 100%); /* Chrome10+,Safari5.1+ */
17 | background: -o-linear-gradient(top, rgba(117,163,25,1) 0%,rgba(163,194,102,1) 100%); /* Opera 11.10+ */
18 | background: -ms-linear-gradient(top, rgba(117,163,25,1) 0%,rgba(163,194,102,1) 100%); /* IE10+ */
19 | background: linear-gradient(top, rgba(117,163,25,1) 0%,rgba(163,194,102,1) 100%); /* W3C */
20 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#75a319', endColorstr='#a3c266',GradientType=0 ); /* IE6-8 */
21 | -moz-box-shadow: 0 4px 6px rgba(0, 0, 0, 0.4);
22 | -webkit-box-shadow: 0 4px 6px rgba(0, 0, 0, 0.4);
23 | box-shadow: 0 4px 6px rgba(0, 0, 0, 0.4);
24 | }
25 |
26 | #header {
27 | position: relative;
28 | margin: 0 auto;
29 | text-align: left;
30 | width: 960px;
31 | color: #333;
32 | }
33 |
34 | #links {
35 | position: absolute;
36 | right: 10px;
37 | }
38 |
39 | #main-container {
40 | background-color: white;
41 | background-color: rgba(255, 255, 255, 0.9);
42 | margin: 10px auto 0;
43 | width: 960px;
44 | min-height: 500px;
45 | text-align: left;
46 | padding: 20px;
47 | font-size: 0.875em;
48 | }
49 |
50 | #toc {
51 | float: right;
52 | font-size: 0.9em;
53 | width: 240px;
54 | padding: 5px 15px;
55 | margin-top: 1em;
56 | margin-left: 20px;
57 | border: 1px solid #DDD;
58 | background-color: #fdfdfd;
59 | -moz-box-shadow: 0 0 4px rgba(0, 0, 0, 0.4);
60 | -webkit-box-shadow: 0 0 4px rgba(0, 0, 0, 0.4);
61 | box-shadow: 0 0 4px rgba(0, 0, 0, 0.4);
62 | }
63 |
64 | #toc ol {
65 | padding-left: 20px;
66 | }
67 |
68 | a {
69 | text-decoration: none;
70 | color: #708d00;
71 | }
72 |
73 | a:hover, a:active {
74 | text-decoration: underline;
75 | }
76 |
77 | a:visited {
78 | color: #7c9d00;
79 | }
80 |
81 | h1 {
82 | color: #637e00;
83 | margin-bottom: 1.25em;
84 | }
85 |
86 | h2 {
87 | color: #708d00;
88 | margin-top: 1.5em;
89 | margin-bottom: 1em;
90 | }
91 |
92 | h3 {
93 | color: #7c9d00;
94 | margin-top: 1em;
95 | margin-bottom: 0.75em;
96 | }
97 |
98 | h4 {
99 | color: #89a719;
100 | }
101 |
102 | p {
103 | margin: 0.75em 0;
104 | }
105 |
106 | #all_links {
107 | display: none;
108 | position: absolute;
109 | top: 3em;
110 | right: 0;
111 | background-color: white;
112 | background-color: rgba(255, 255, 255, 0.95);
113 | width: 350px;
114 | height: 500px;
115 | overflow: auto;
116 | z-index: 100;
117 | padding: 20px;
118 |
119 | -moz-box-shadow: 0 0 10px rgba(0, 0, 0, 0.4);
120 | -webkit-box-shadow: 0 0 10px rgba(0, 0, 0, 0.4);
121 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.4);
122 | -webkit-border-radius: 25px;
123 | -webkit-border-top-right-radius: 0;
124 | -moz-border-radius: 25px;
125 | -moz-border-radius-topright: 0;
126 | border-radius: 25px;
127 | border-top-right-radius: 0;
128 | }
129 |
130 | #all_links a {
131 | display: block;
132 | margin: 0.5em 0;
133 | }
134 |
135 | #all_links_toggler {
136 | display: inline-block;
137 | position: absolute;
138 | top: 1em;
139 | right: 0;
140 | cursor: pointer;
141 | padding: 5px 10px;
142 | border: 1px solid #555;
143 | -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.4);
144 | -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.4);
145 | box-shadow: 0 0 3px rgba(0, 0, 0, 0.4);
146 | text-decoration: none;
147 | font-size: 0.9em;
148 | color: #EEE;
149 | background: rgb(119,119,119); /* Old browsers */
150 | background: -moz-linear-gradient(top, rgba(119,119,119,1) 0%, rgba(51,51,51,1) 100%); /* FF3.6+ */
151 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(119,119,119,1)), color-stop(100%,rgba(51,51,51,1))); /* Chrome,Safari4+ */
152 | background: -webkit-linear-gradient(top, rgba(119,119,119,1) 0%,rgba(51,51,51,1) 100%); /* Chrome10+,Safari5.1+ */
153 | background: -o-linear-gradient(top, rgba(119,119,119,1) 0%,rgba(51,51,51,1) 100%); /* Opera 11.10+ */
154 | background: -ms-linear-gradient(top, rgba(119,119,119,1) 0%,rgba(51,51,51,1) 100%); /* IE10+ */
155 | background: linear-gradient(top, rgba(119,119,119,1) 0%,rgba(51,51,51,1) 100%); /* W3C */
156 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#777777', endColorstr='#333333',GradientType=0 ); /* IE6-8 */
157 | }
158 |
159 | #all_links_toggler.shown {
160 | background: rgb(51,51,51); /* Old browsers */
161 | background: -moz-linear-gradient(top, rgba(51,51,51,1) 0%, rgba(119,119,119,1) 100%); /* FF3.6+ */
162 | background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,rgba(51,51,51,1)), color-stop(100%,rgba(119,119,119,1))); /* Chrome,Safari4+ */
163 | background: -webkit-linear-gradient(top, rgba(51,51,51,1) 0%,rgba(119,119,119,1) 100%); /* Chrome10+,Safari5.1+ */
164 | background: -o-linear-gradient(top, rgba(51,51,51,1) 0%,rgba(119,119,119,1) 100%); /* Opera 11.10+ */
165 | background: -ms-linear-gradient(top, rgba(51,51,51,1) 0%,rgba(119,119,119,1) 100%); /* IE10+ */
166 | background: linear-gradient(top, rgba(51,51,51,1) 0%,rgba(119,119,119,1) 100%); /* W3C */
167 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#333333', endColorstr='#777777',GradientType=0 ); /* IE6-8 */
168 | }
169 |
170 | .bq code, .code {
171 | font-family: 'Monaco', 'Inconsolata', 'Courier New', 'Courier', monospace;
172 | color: #444;
173 | }
174 |
175 | code {
176 | font-family: 'Monaco', 'Inconsolata', 'Courier New', 'Courier', monospace;
177 | color: #666;
178 | padding: 0 0.25em;
179 | }
180 |
181 | .code, .bq {
182 | border: 1px solid #ddd;
183 | padding: 0 20px 1em;
184 | overflow: auto;
185 | background-color: #fbfbfb;
186 | }
187 |
188 | table.wiki-table {
189 | border-collapse: collapse;
190 | }
191 |
192 | table.wiki-table th {
193 | background-color: #7c9d00;
194 | color: white;
195 | padding: 3px 5px;
196 | text-align: center;
197 | border: 1px solid #7c9d00;
198 | }
199 |
200 | table.wiki-table tr.table-odd {
201 | background-color: white;
202 | }
203 |
204 | table.wiki-table tr.table-even {
205 | background-color: #F2F5E6;
206 | }
207 |
208 | table.wiki-table td {
209 | padding: 3px 10px;
210 | border: 1px solid #7c9d00;
211 | }
--------------------------------------------------------------------------------
/src/en/performanceTuning.gdoc:
--------------------------------------------------------------------------------
1 | h1. Tune the performance of Grails apps
2 |
3 | For many developers, a standard Grails application works plenty fast enough, particularly with judicious use of caching. Yet there is almost always a trade-off between convenience and flat out speed. So if you need to increase the number of concurrent users that can be handled or increase the number of requests per second that are processed, read on.
4 |
5 | But! Before you do, please remember that every application is different. Sometimes an application is slow simply because it's executing way more queries than it needs to. For that reason, you should always profile your application to find out what's happening. The following suggestions only really apply if you discover that it's not your application code that's the problem.
6 |
7 | h2. Increase number of concurrent users
8 |
9 | If you know that you're going to have quite a few active users at any one time (hundreds -> thousands), then there are some simple steps that you can take to ensure that they can all happily use your app at the same time.
10 |
11 | h3. Disable Open Session In View filter
12 |
13 | A standard Grails application with the Hibernate plugin installed has a special request interceptor enabled that opens a Hibernate session for every request and keeps it open until the view is rendered. This is convenient for the developer but acts as a drag on the number of concurrent requests that can be processed as each Hibernate session fetches a database connection.
14 |
15 | The simplest way to disable the filter is to remove the Hibernate plugin. Of course, this isn't ideal if you actually use GORM/Hibernate! The alternative is to write a no-op interceptor and configure it as the @openSessionInViewInterceptor@ bean in @resources.groovy@. [TODO Add code for no-op interceptor]
16 |
17 | Be warned that if you disable the interceptor, the standard Grails scaffolding will break and you will also need to ensure that you manage the sessions yourself. Fortunately, if you perform all database access through transactional services, you're already covered. Still, even then you will need to make sure that any collections you access from your views are eagerly loaded.
18 |
19 | h3. Flash and sessions
20 |
21 | As soon as you use flash scope, Grails creates an HTTP session. The lifetime of that session depends on what is configured in web.xml, but by default it's 30 mins. As you can see, if lots of people hit flash-enabled pages at the same time (or within a half-hour window), your application will end up with a large number of active sessions.
22 |
23 | One 'fix' is to reduce the session timeout to something much lower. You can do this by running
24 |
25 | {code}
26 | grails install-templates
27 | {code}
28 |
29 | and then editing @src/templates/war/web.xml@:
30 |
31 | {code:xml}
32 |
33 |
34 | 1
35 |
36 | {code}
37 |
38 | This isn't ideal though if you want users to log in and not have to log in every minute! In such cases, you should probably avoid using flash in pages that don't require a logged in user.
39 |
40 | h3. XML and JSON rendering
41 |
42 | The markup builder syntax for generating XML responses is very convenient. But it's not terribly fast. The same goes for JSON. If you discover that the rendering time is proving a bottleneck, first try the @as XML@ and @as JSON@ feature. If you still need improvements, consider using alternative libraries such as Jackson for JSON.
43 |
44 | h2. Improve throughput
45 |
46 | Sometimes the only metric that counts is the number of requests per second. This section details some of the steps you can take to crank up those numbers.
47 |
48 | h3. Disable Hibernate caches
49 |
50 | The Hibernate's legacy 2nd-level cache interface (cache provider api) is a source of monitor (thread) blocking. So for high throughput you should disable the 2nd-level cache completely by removing
51 |
52 | {code}
53 | hibernate {
54 | cache.use_second_level_cache = true
55 | cache.use_query_cache = true
56 | cache.provider_class = 'net.sf.ehcache.hibernate.EhCacheProvider'
57 | }
58 | {code}
59 |
60 | from @DataSource.groovy@. Unless...you are using Grails 2.x+ with Ehcache. This is because those versions of Grails will automatically use a new Hibernate API that _doesn't_ block. But this only happens with Ehcache.
61 |
62 | The Hibernate query cache is problematic on it's own. For a start, it doesn't work well with tables whose data changes frequently. In fact, queries can be _slower_ if you use the cache in these circumstances. You should only really use the query cache for reference datathat doesn't change often. In addition, there is a [Hibernate issue|https://hibernate.onjira.com/browse/HHH-5927] for versions prior to 4.1.1 that results in threads blocking.
63 |
64 | Ultimately, you are probably better off caching at the service and view layer via the [Cache plugin|http://grails.org/plugin/cache].
65 |
66 | h3. Command objects
67 |
68 | Prior to Grails 2, command object binding could prove a significant bottleneck to throughput. If that's the case for your application, then consider changing your action code from something like
69 |
70 | {code}
71 | def save = { UserCommand userCommand ->
72 | ...
73 | }
74 | {code}
75 |
76 | to
77 |
78 | {code}
79 | def save = { ->
80 | UserCommand userCommand = new UserCommand()
81 | bindData(userCommand, params)
82 | ...
83 | }
84 | {code}
85 |
86 | Just to clarify again, this is not a problem in Grails 2 and above.
87 |
88 | h2. Benchmark happy
89 |
90 | People like benchmarks, and that's fair enough because they're often the only source of information for how well something will perform. But they often _don't_ reflect real world usage. Still, if you are doing some benchmarks, here are some tips to get the best numbers (and of course these can help in production apps too!).
91 |
92 | h3. Warm up the JVM
93 |
94 | In benchmarking Grails you usually have to first do about 20000 requests and give the JVM a breath for about 10 seconds after that, possibly because the JVM delays background compilation when CPU usage is high and it does JIT compilation during this sleep time. After this, the throughput performance is usually about 5x better than in the beginning.
95 |
96 | h3. JVM settings
97 |
98 | Have you set Permgen size to something reasonable (for example: -XX:PermSize=128M -XX:MaxPermSize=256M)? The @run-app@ and @run-war@ commands do this automatically, but make sure your production servlet container does the same.
99 |
100 | Example settings for Tomcat (in $CATALINA_HOME/bin/setenv.sh):
101 |
102 | {code}
103 | CATALINA_OPTS="-server -noverify -Xshare:off -Xms512M -Xmx512M -XX:MaxPermSize=256M -XX:PermSize=128M -XX:+UseParallelGC"
104 | CATALINA_OPTS="${CATALINA_OPTS} -Dgrails.env=production"
105 | CATALINA_OPTS="${CATALINA_OPTS} -Djava.net.preferIPv4Stack=true -XX:+EliminateLocks -XX:+UseBiasedLocking"
106 | # optional setting: MaxJavaStackTraceDepth, it reduces performance overhead of long exception stacktraces by limiting their size to 100 stacktrace elements
107 | # You should eliminate all exceptions (even catched) to get good Grails performance
108 | # always use some JVM profiler (for example Yourkit YJP) to see if any exceptions are created during normal program flow
109 | # Grails and Groovy create some exceptions in initializations but after a few requests, no new exceptions should be created.
110 | CATALINA_OPTS="${CATALINA_OPTS} -XX:MaxJavaStackTraceDepth=100"
111 | {code}
112 |
113 | The JVM version can also have an impact, so be sure your JVM is up to date.
114 |
115 | h3. OS
116 |
117 | Have you checked if your OS starts swapping? (Monitoring in Linux: "vmstat 1", make sure "swap si / so" are 0 during the benchmark).
118 | For Linux, use should usually tune swappiness for running a JVM. In /etc/sysctl.conf:
119 | {code}
120 | vm.swappiness=5
121 | (changing temporarily/immediately: "echo 5 | sudo tee /proc/sys/vm/swappiness")
122 | Checking current value: cat /proc/sys/vm/swappiness
123 | {code}
124 |
125 | vm.swappiness defaults to 60 on many distros and that means that the OS starts swapping after 60% of memory is used. Since the JVM allocates a lot of memory, it will usually cause some swapping if you don't tune swappiness.
126 |
127 | You might also have to tune the Linux OS TCP/IP settings if "netstat -an" still shows a lot of hanging connections after adding the id-parameter to grails-rest calls.
128 |
--------------------------------------------------------------------------------
/src/en/upgradeToGrails2.gdoc:
--------------------------------------------------------------------------------
1 | h1. Upgrade to Grails 2
2 |
3 | There are always some breaking changes with any major version change of a framework. This document will navigate you through the changes you may need to make in order to get an existing Grails 1.3.x application working with Grails 2.0. Some changes will apply to all projects. Others only affect a few projects. The complexity of upgrading an existing application also depends on what plugins are installed, so any plugins that are known to work with Grails 2 are included at the end.
4 |
5 | h2. First steps
6 |
7 | The very first thing you should do is delete the project's 'target' directory, and if your project working directory isn't specific to a version of Grails, delete that too (it's under a @@ path by default). Then, with Grails 2 execute:
8 |
9 | bc.
10 | grails upgrade --force
11 |
12 | This will ensure you have the latest versions of the JSP taglib definition files and, most importantly, the latest applicationContext.xml.
13 |
14 | The @web.xml@ file has also changed, but this only affects projects that have a template @web.xml@ in the 'src/templates' directory. If that's the case, work out what changes were made to it, re-run @grails install-templates@, and then apply the changes to the new web descriptor.
15 |
16 | If you want to use the new interactive console extensively (and why wouldn't you?) then be prepared to up the heap and permgen space for your application:
17 |
18 | bc.
19 | export GRAILS_OPTS="-Xmx700m -XX:MaxPermSize=384m"
20 |
21 | for example. To fine tune these numbers, you can run something like the JDK jconsole command to see how much memory your application is using when running the interactive console.
22 |
23 | h2. Persistence
24 |
25 | The persistence layer has seen a lot of change over the last year or two, not least because GORM is now available for multiple data stores, not just SQL via Hibernate. Still, most domain models won't have to change much if at all.
26 |
27 | h3. New in-memory database
28 |
29 | Many projects probably use the default HSQLDB database for development. Grails 2 has switched to H2 as the default instead, and so if you try to run your application you'll see this warning:
30 |
31 | bc.
32 | Database driver [org.hsqldb.jdbcDriver] for HSQLDB not found. Since Grails 2.0 H2 is now the default database. You need to either add the 'org.h2.Driver' class as your database driver and change the connect URL format (for example 'jdbc:h2:mem:devDb') in DataSource.groovy or add HSQLDB as a dependency of your application.
33 |
34 | As the message explains, you can fix this in one of two ways. The quickest is to add this line to @BuildConfig.groovy@:
35 |
36 | {code}
37 | ...
38 | grails.project.dependency.resolution = {
39 | ...
40 | dependencies {
41 | runtime "hsqldb:hsqldb:1.8.0.10"
42 | ...
43 | }
44 | }
45 | {code}
46 |
47 | The above version of the HSQLDB driver is included with the Grails distribution, so the project doesn't even need to pull it from the internet. If you'd prefer to upgrade to H2, then modify the HSQLDB driver class name and connection URLs in @DataSource.groovy@:
48 |
49 | {code}
50 | dataSource {
51 | driverClassName = "org.h2.Driver"
52 |
53 | // In memory database
54 | url = "jdbc:h2:mem:devDb;MVCC=TRUE"
55 |
56 | // File-based database
57 | //url = "jdbc:h2:prodDb;MVCC=TRUE"
58 | ...
59 | }
60 | {code}
61 |
62 | If you go for this approach, there's no need to add the H2 driver JAR as an explicit dependency as it is included vi the @inherits("global")@ directive.
63 |
64 | h3. Abstract domain classes
65 |
66 | Consider this model:
67 |
68 | !upgradeToGrails2/abstract-domain-inheritance.png!
69 |
70 | where the @Person@ domain class is declared as abstract. Before Grails 2, this model would result in two separate tables: one for @Employee@ and one for @Manager@. This doesn't really make a lot of sense, because the two domain classes share common properties from @Person@, so Grails 2 will now create a single @Person@ table that @Employee@ and @Manager@ use.
71 |
72 | If you have existing data based on the old model, this change will break your application. You have a couple of options:
73 |
74 | # migrate your data to the new model with a shared table; or
75 | # move the abstract domain class, e.g. @Person@, to the 'src/groovy' directory.
76 |
77 | Of these, the latter is much simpler.
78 |
79 | h3. Problematic property names
80 |
81 | Some domain class property names will cause issues for various reasons:
82 |
83 | * @environment@
84 | * @load@
85 | * @get@
86 | * @list@
87 | * @find@
88 | * @findAll@
89 | * @where@
90 |
91 | The problem with @environment@ is fixed in 2.0.1. The problem with domain class properties that match the names of static GORM methods will be fixed in a future version.
92 |
93 | h2. The web layer
94 |
95 | Grails 2 introduces quite a few new features to controllers and other parts of the web layer, but few breaking changes. One of the most significant changes is that actions can now be declared as public methods and we recommend you migrate your existing code to this approach if you can. However, this means that if you have public methods in controllers already, they will suddenly be exposed as actions - probably not what you want. Be sure to change those methods to either @private@ or @protected@ scope.
96 |
97 | h3. Scaffolding and error views
98 |
99 | Grails 2 introduces some nice HTML5 scaffolding and an updated error view. Both of these work perfectly out of the box for a new project, but not when you upgrade an existing project. The simplest thing to do is create a new Grails 2 project and then copy the relevant files to your existing one:
100 |
101 | bc.
102 | cp /web-app/css/main.css /web-app/
103 | cp /grails-app/views/error.gsp /grails-app/views/
104 |
105 | *Note* If you have customised either file, then the upgrade process is trickier as you have to re-apply your changes to the new files. In fact, it's probably better to rename 'main.css' to something else (such as 'app.css') and use that for your own views. In other words, leave 'main.css' for the scaffolding.
106 |
107 | h3. Redirects
108 |
109 | In order to allow code to modify the response after issuing a redirect, Grails had to bypass the standard Servlet @sendRedirect()@ method. As a side-effect, the @redirect()@ is now dependent on the @grails.serverURL@ configuration setting. If this doesn't match the URL of your application, redirects will stop working.
110 |
111 | The simplest way to avoid this problem is to remove the setting unless you need it. If you need it (usually for production deployments) then the value should already match the URL of your application. This mostly impacts development where old projects often have a legacy value that doesn't work.
112 |
113 | Another side-effect is that you can no longer use the @response.isCommitted()@ method to determine whether a redirect has taken place. Instead, there is a new @request.isRedirected()@ method that you should use - *note* that the new method is on @request@ rather than @response@\!
114 |
115 | h3. Content negotiation
116 |
117 | Prior to version 2, Grails would factor in the request content type when performing content negotiation. However, the request content type is a bad basis for determining the response content type - that's what the @Accept@ header is for! So, Grails 2 ignores it. This may break your usage of @withFormat()@ if you depend on selection by request content type.
118 |
119 | If you want to do something based on the request content type, then use the @withFormat()@ method on the @request@ object instead:
120 |
121 | {code}
122 | request.withFormat {
123 | xml {
124 | // Do something for XML request content
125 | }
126 | json {
127 | // Do something for JSON request content
128 | }
129 | }
130 | {code}
131 |
132 | h3. AJAX tags + Prototype.js
133 |
134 | Grails has packaged Prototype.js by default for a long time. That finally changed with Grails 2 and in fact _no_ Javascript library is included directly any more. Instead, a new Grails 2 project will automatically have the jQuery _plugin_ as a dependency.
135 |
136 | What this means for existing projects is that if you use the adaptive AJAX tags with Prototype.js, you will need to add the new [Prototype plugin|http://grails.org/plugin/prototype] as a dependency.
137 |
138 | h3. Installing Resources plugin
139 |
140 | The [Resources plugin|http://grails.org/plugin/resources] is a great way of managing static web resources such as CSS and Javascript files. Many pre-2 projects are probably already using it. If that's the case, be warned that Grails 2 is Resources-aware and modifies the behaviour of the @@ and @@ tags if the plugin is installed.
141 |
142 | All this means in reality is that you should use the @@ tags for all your responses, although AJAX responses are a bit of a special case.
143 |
144 | We don't really recommend that you include markup and inline Javascript in AJAX responses. However, if you do, then switch to a raw @