[ { "bintrayPackage": { "name": "actuator-ui", "repo": "plugins", "owner": "dmahapatro", "desc": "Grails actuator-ui plugin", "labels": [ "spring-boot-actuator", "health-check" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/dmahapatro/grails-actuator-ui/issues", "latestVersion": "1.1", "updated": "2016-09-04T04:00:40.855Z", "systemIds": [ "org.grails.plugins:actuator-ui" ], "vcsUrl": "https://github.com/dmahapatro/grails-actuator-ui" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "
\n
\n
\n

\"Build\n\"download\"

\n
\n
\n

Spring Actuator is a tool which monitors application’s health, metrics and lots of other metadata information about the application.\nThis plugin projects those information in a UI which makes it very user friendly to know the status of the application.

\n
\n
\n
\n
\n

Demo

\n
\n
\n

DEMO

\n
\n
\n
\n
\n

Prerequisites

\n
\n
\n
    \n
  • \n

    For Grails 3.0.* version 0.2 can be used

    \n
  • \n
  • \n

    For Grails 3.1.* version 1.0 should be used

    \n
  • \n
\n
\n
\n
\n
\n

Configuration

\n
\n
\n

build.gradle

\n
\n
\n
\n
repositories {\n    maven {\n        url  \"http://dl.bintray.com/dmahapatro/plugins\"\n    }\n}\n\ndependencies {\n    ...\n    compile \"org.grails.plugins:actuator-ui:1.1\"\n}
\n
\n
\n
\n
\n
\n

How To

\n
\n
\n

To access the actuator endpoints you can simply hit /actuator/dashboard at root context.

\n
\n
\n
\n
http://localhost:8080/sample/actuator/dashboard
\n
\n
\n
\n

where /sample is the root context of the application. For a base Grails app where root context is /, the url will be

\n
\n
\n
\n
http://localhost:8080/actuator/dashboard
\n
\n
\n
\n
\n
\n

Secured

\n
\n
\n

Actuator UI is targeted for Admins and normal users. Taking ROLE into consideration this plugin can be easily integrated with spring security core plugin. For example with a mapping like the below in application.yml would secure /actuator/dashboard endpoint.

\n
\n
\n
\n
grails:\n    plugin:\n        springsecurity:\n            userLookup:\n                userDomainClassName: auth.User\n                authorityJoinClassName: auth.UserRole\n            authority:\n                className: auth.Role\n            controllerAnnotations:\n                staticRules:\n                    - pattern: '/actuatordashboard/**'\n                      access: ['hasRole(\"ROLE_ADMIN\")']\n                    - pattern: '/actuator/**'\n                      access: ['hasRole(\"ROLE_ADMIN\")']
\n
\n
\n
\n

Avatar support

\n
\n

Actuator-ui ships with Gravatar plugin. It will render a gravatar image under the following circumstances:

\n
\n
\n
    \n
  • \n

    Spring Security is installed

    \n
  • \n
  • \n

    The user is logged in

    \n
  • \n
\n
\n
\n

Gravatar is enabled for actuator-ui by default. To disable Gravatar in actuator-ui, you should add the following to application’s application.yml.

\n
\n
\n
\n
grails:\n    plugin:\n        actuator:\n            gravatar:\n                disabled: true
\n
\n
\n
\n

To modify the default rating and gravatar fallback image please refer to the Gravatar Plugin Documentation

\n
\n
\n\n\n\n\n\n
\n
Note
\n
\nWhen spring security and gravatar are enabled, the plugin grabs the username to look for the gravatar. In this case the username should be a valid email registered in Gravatar otherwise it will fallback to the default gravatar image.\n
\n
\n
\n
\n

Sample

\n
\n

Sample apps with Spring Security Core integration:

\n
\n
\n
    \n
  • \n

    Run actuator-ui-app available as sub project in this plugin repository.

    \n
  • \n
  • \n

    Run sample app created by Bertrand Goetzmann.

    \n
  • \n
\n
\n
\n
\n

v1.1

\n
\n
    \n
  • \n

    Gravatar support added for logged in user.

    \n
  • \n
\n
\n
\n
\n

v1.0

\n
\n
    \n
  • \n

    Grails upgraded to v3.1.10

    \n
  • \n
\n
\n
\n
\n

v0.2

\n
\n
    \n
  • \n

    Integrated console plugin. A link is provided in the header bar to open console via console plugin. Appropriate version of console plugin has to be installed in the app which uses this plugin. If console plugin is added as a dependency then actuator dashboard should show console link next to the logged in user in top right corner.

    \n
  • \n
  • \n

    Items are searchable now. Search for a particular bean, mapping, calls etc.

    \n
  • \n
  • \n

    Paginated list of items.

    \n
  • \n
\n
\n
\n
\n
\n
\n

TODO

\n
\n
\n
    \n
  • \n

    Add charts on Garbage Collection metrics.

    \n
  • \n
  • \n

    Add support for custom address and port.

    \n
  • \n
\n
\n
\n
" }, { "displayName": "airbrake", "bintrayPackage": { "name": "airbrake-grails", "repo": "plugins", "owner": "bostanio", "desc": "Airbrake Client for Grails", "labels": [ "airbrake" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/cavneb/airbrake-grails/issues", "latestVersion": "1.0.0.RC1", "updated": "2016-03-31T13:31:55.050Z", "systemIds": [ "org.grails.plugins:airbrake-grails" ], "vcsUrl": "https://github.com/cavneb/airbrake-grails" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Airbrake Plugin for Grails

\n

This is the notifier plugin for integrating grails apps with Airbrake.

\n

When an uncaught exception occurs, Airbrake will POST the relevant data to the Airbrake server specified in your environment.

\n

Installation & Configuration

\n

Add the following to your BuildConfig.groovy

\n
compile ":airbrake:0.9.4"\n
\n

Once the plugin is installed, you need to provide your Api Key in Config.groovy file:

\n
grails.plugins.airbrake.apiKey = 'YOUR_API_KEY'\n
\n

Usage

\n

Once you have installed and configured the plugin there is nothing else to do. Uncaught exceptions will be logged by log4j and those errors will be reported to Airbrake. However, the plugin also exposes a few other ways to send errors to airbrake.

\n

Logging Errors with Exceptions

\n

Manually logging messages at the error level and including an Exception triggers an error notification to airbrake:

\n
class SomeController\n\tdef someAction() {\n\t\ttry {\n\t\t\tsomethingThatThrowsAnException()\n\t\t} catch(e) {\n\t\t\tlog.error('An error occured', e)\n\t\t}\n\t}\n
\n

(See the section below on configuring the plugin to including errors without exceptions.)

\n

AirbakeService

\n

The plugin also exposes an airbrakeService which can be dependency injected into your Grails classes. The service allows you to send error notifications directly to Airbrake without logging anything to log4j. It has a notify method that takes a Throwable parameter and an optional Map of arguemnts. The next example shows both in use:

\n
class SomeController\n\tdef airbrakeService\n\t\n\tdef someAction() {\n\t\ttry {\n\t\t\tsomethingThatThrowsAnException()\n\t\t} catch(e) {\n\t\t\tairbrakeService.notify(e, [errorMessage: 'An error occurred'])\n\t\t}\n\t}\n\n\tdef anotherAction() {\n\t\tif (somethingWentWrong()) {\n\t\t\tairbrakeService.notify(null, [errorMessage: 'Something went wrong'])\n\t\t}\n\t}\n
\n

Advanced Configuration

\n

The Api Key is the minimum requirement to report errors to Airbrake. However, the plugin supports several other configuration options. The full list of configuration options is:

\n
grails.plugins.airbrake.apiKey\ngrails.plugins.airbrake.enabled\ngrails.plugins.airbrake.env\ngrails.plugins.airbrake.includeEventsWithoutExceptions\ngrails.plugins.airbrake.paramsFilteredKeys\ngrails.plugins.airbrake.sessionFilteredKeys\ngrails.plugins.airbrake.cgiDataFilteredKeys\ngrails.plugins.airbrake.host\ngrails.plugins.airbrake.port\ngrails.plugins.airbrake.secure\ngrails.plugins.airbrake.async\ngrails.plugins.airbrake.asyncThreadPoolSize\ngrails.plugins.airbrake.stackTraceFilterer\ngrails.plugins.airbrake.excludes\n
\n

Enabling/Disabling Notifications

\n

By default all errors are sent to Airbrake. However, you can disable error notifications (essentially disabling the plugin) by setting grails.plugins.airbrake.enabled = false. For example to disable error notificaitons in development and test environments you might have the following in Config.groovy:

\n
grails.plugins.airbrake.apiKey = 'YOUR_API_KEY'\nenvironments {\n\tdevelopment {\n\t\tgrails.plugins.airbrake.enabled = false\n\t}\n\ttest {\n\t\tgrails.plugins.airbrake.enabled = false\n\t}\n
\n

Disabling Notifications by Exception Type

\n

For example, to disable notifications caused by IllegalArgumentException and IllegalStateException, configure

\n
grails.plugins.airbrake.excludes = ['java.lang.IllegalArgumentException', 'java.lang.IllegalStateException']\n
\n

each entry in the list will be converted to a Pattern and matched against the exception class name, so the following\nwould also exclude these two exceptions:

\n
grails.plugins.airbrake.excludes = ['java.lang.Illegal.*Exception']\n
\n

Runtime Enabling/Disabling

\n

If you wish to enable/disable notifications at runtime you have a couple of options

\n\n

Setting the Environment

\n

By default, the environment name used in Airbrake will match that of the current Grails environment. To change this default, set the env property:

\n
grails.plugins.airbrake.env = grails.util.Environment.current.name[0..0] // Airbrake env name changed from default value of Development/Test/Production to D/T/P\n
\n

Including all events logged at the Error level

\n

By default only uncaught errors or errors logged with an exception are reported to Airbrake. It is often convenient to loosen that restriction so that all messages logged at the Error level are reported to Airbrake. This often most useful in src/java or src/groovy classes that can more easily have a log4j logger than get accees to the dependency injected airbrakeService.

\n

With the following line in Config.groovy:

\n
grails.plugins.airbrake.includeEventsWithoutExceptions = true\n
\n

then logged errors get reported to Airbrake:

\n
@Log4j\nclass SomeGroovyClass {\n\tdef doSomething() {\n\t\tif (somethingWentWrong()) {\n\t\t\tlog.error('Something went wrong')\n\t\t}\n\t}\n}\n
\n

Note: It might be reasonable to have this setting true by default but for backwards compatibility with previous versions of te plugin the default is false.

\n

Filtering Parameters sent to Airbrake

\n

To prevent certain parameters from being sent to Airbrake you can configure a list of parameter names to filter out. The configuration settings paramsFilteredKeys, sessionFilteredKeys and cgiFilteredKeys filter the params, session and cgi data sent to Airbrake.\nFor example to prevent any web request parameter named 'password' from being included in the notification to Airbrake you would use the following configuration:

\n
grails.plugins.airbrake.paramsFilteredKeys = ['password']\n
\n

Each configuration option also supports regular expression matching on the keys. For example the following configuration would prevent all session data from being sent to Airbrake:

\n
grails.plugins.airbrake.sessionFilteredKeys = ['.*']\n
\n

Custom Airbrake Host, Port and Scheme

\n

If you are running the Airbrake server locally (or a clone thereof, e.g. Errbit), you will need to customise the server URL, port, scheme, etc.\nFor example to change the server host and port, add the following configuration parameters:

\n
grails.plugins.airbrake.host = 'errbit.example.org'\ngrails.plugins.airbrake.port = 8080\n
\n

Adding Custom Data to Error Notifications

\n

Supplying User Data

\n

Airbrake allows certain User data to be supplied with the notice. To set the current users data to be included in all notifications use the airbrakeService.addNoticeContext method to set a map of userData.\nThe supported keys are id, name, email and username

\n
airbrakeService.addNoticeContext(id: '1234', name: 'Bugs Bunny', email: 'bugs@acme.com', username: 'bugs')\n
\n

In most web apps the simplest way to provide this context is in a Grails filter. For example if you are using SpringSecurity add the following AirbrakeFilter.groovy in grails-app/conf

\n
class AirbrakeFilters {\n    def airbrakeService\n    def springSecurityService\n\n    def filters = {\n        all(uri: '/**') {\n            before = {\n                def user = springSecurityService.currentUser\n                if (user) {\n                   airbrakeService.addNoticeContext(user: [id: user.id, name: user.name, email: user.email, username: user.username ])\n                }\n            }\n        }\n    }\n}\n
\n

Synchronous/Asynchronous notifications

\n

By default, notifications are sent to Airbrake asynchronously using a thread-pool of size 5. To change the size of this thread\npool set the following config parameter:

\n
// double the size of the pool\ngrails.plugins.airbrake.asyncThreadPoolSize = 10\n
\n

To have the notifications sent synchronously, set the async parameter to false:

\n
// send notifications synchronously\ngrails.plugins.airbrake.async = false\n
\n

Custom Asynchronous Handler

\n

To send the notifications asynchronously using a custom handler, use the async configuration option.\nThis configuration takes a closure with two parameters the Notice to send and the grailsApplication. The asynchronous handler should simply call airbrakeService.sendNotice(notice) to deliver the notification.

\n

This plugin does not introduce a default choice for processing notices asynchronously. You should choose a method that suits your application.\nYou could just create a new thread or use a scheduler/queuing plugin such as Quartz or Jesque

\n

For example if you are using the Quartz plugin you can send notifications asynchronously using the following setting in Config.groovy

\n
grails.plugins.airbrake.async = { notice, grailsApplication ->\n    AirbrakeNotifyJob.triggerNow(notice: notice)\n}\n
\n

and the AirbrakeNotifyJob is defined in grails-app\\jobs something like this:

\n
class AirbrakeNotifyJob {\n    def airbrakeService\n\n    def execute(JobExecutionContext context) {\n        Notice notice = context.mergedJobDataMap.notice\n        if (notice) {\n            airbrakeService.sendNotice(notice)\n        }\n    }\n}\n
\n

Stack Trace Filtering

\n

By default all stack traces are filtered using an instance of org.codehaus.groovy.grails.exceptions.DefaultStackTraceFilterer to remove common Grails and java packages.\nTo provide custom stack trace filtering simple configure an instance of a class that implements the interface org.codehaus.groovy.grails.exceptions.StackTraceFilterer in Config.groovy

\n
grails.plugins.airbrake.stackTraceFilterer = new MyCustomStackTraceFilterer()\n
\n

Compatibility

\n

This plugin is compatible with Grails version 2.0 or greater. A backport to Grails 1.3 is available on the [grails-1.3 branch] (https://github.com/cavneb/airbrake-grails/tree/grails-1.3).

\n

Release Notes

\n\n

Contributing

\n
    \n
  1. Fork it
  2. \n
  3. Create your feature branch (git checkout -b my-new-feature)
  4. \n
  5. Commit your changes (git commit -am 'Added some feature')
  6. \n
  7. Push to the branch (git push origin my-new-feature)
  8. \n
  9. Create new Pull Request
  10. \n
\n

Kudos

\n

The origin version of this plugin was written by Phuong LeCong (https://github.com/plecong/grails-airbrake).\nSince then it has undergone significant refactoring and updates inspired by the Ruby Airbrake gem (https://github.com/airbrake/airbrake)

\n" }, { "bintrayPackage": { "name": "ajax-tags", "repo": "plugins", "owner": "grails", "desc": "Grails ajax-tags plugin", "labels": [ "ajax" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails3-plugins/ajax-tags/issues", "latestVersion": "1.0.0", "updated": "2016-04-01T15:35:44.151Z", "systemIds": [ "org.grails.plugins:ajax-tags" ], "vcsUrl": "https://github.com/grails3-plugins/ajax-tags" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": null }, { "displayName": "ajax-dependency-selection", "bintrayPackage": { "name": "ajaxdependancyselection", "repo": "maven", "owner": "vahid", "desc": "Grails ajaxdependancyselection plugin", "labels": [ "ajax" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/vahidhedayati/ajaxdependancyselection/issues", "latestVersion": "1.3", "updated": "2016-06-28T14:58:54.722Z", "systemIds": [ "org.grails.plugins:ajaxdependancyselection" ], "vcsUrl": "https://github.com/vahidhedayati/ajaxdependancyselection/" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

ajaxdependancyselection

\n

Side note - similar / related projects

\n\n

Ajaxdependancyselection is a Grails plugin which makes use of jquery to provide either select or auto complete form fields. This can be any combination of either fully dependent objects or full dependent as well as no reference bindings.

\n

A common problem when it comes to making a website is having objects that are independant and when a user selects an option what to do next ? do you refresh the page to update the next set of values or look into some jquery/java scripts to auto update the next set of select option.

\n

Installation:

\n

Add plugin Dependency :

\n
    compile ":ajaxdependancyselection:0.45-SNAPSHOT4"\n
\n

codebase for grails 2.X

\n

Dependency (Grails 3.X) :

\n
    compile "org.grails.plugins:ajaxdependancyselection:1.3"  \n
\n

codebase for grails 2.X

\n

0.43 + Security Configuration:

\n

In order to ensure you only allow this plugin to search desired domainClasses as well as restricted to only search/collect fields that will be used within the plugin calls. Simply add something like this below to your Config.groovy. Covering the full domainClass and its packaging convention the search/collect fields you wish to call from within the plugin calls. This now means anything outside of this scope should fail if anyone attempts to break out of the plugin..

\n
ads {\n\tsecurity = "enabled"\n\twhitelist = [\n\t\t\t[dc:'ajaxdependancyselectexample.MyContinent', collect:'id', search:'continentName'],\n\t\t\t[dc:'ajaxdependancyselectexample.MyCountry', collect:'id', search:'countryName'],\n\t\t\t[dc:'ajaxdependancyselectexample.MyCity', collect:'id', search:'cityName']\n\t]\n}\n
\n

Autocomplete requirements:

\n

To use the autocomplete features simply enable this taglib call:

\n
<ads:loadjui/>\n
\n

Within your layout/main.gsp or a gsp page that uses autoComplete and requires jquery-ui

\n

You can also add:

\n
loadjui='enable'\n
\n

To any ads:autoComplete tags and you should only need to call it once on a given page. So on one of the ads:autoComplete calls should suffice.

\n
Websocket multi-select + auto complete(html5)
\n

boselecta, no jquery and no jquery-ui used. Secure information flow. downside - client needs to have websocket supported browser.

\n

version info:

\n
0.45-SNAPSHOT4/1.0 - various issues https://github.com/vahidhedayati/testads5/issues/1#issuecomment-113842538\n0.45-SNAPSHOT3 - reverted returnPrimarySearch due to filtering issues\n0.45-SNAPSHOT2 - added showSearchField='|' and whatever character to split collect/search fields for auto complete - user request.\n\n0.45/1.0 - Fixed jquey-ui image issues, fixed controller action selection. hardcoded jquery removed from  _selectJs.gsp\n0.44 - a println left in security - as part of upgrade to grails3 (now working) all code has been reviewed and a major tidy up lock down carried out.\n\n0.43 - Security configuration added, you can now define which domainClasses are searchable and what fields can be searched. I can see the initial primary selection still works but this is due to entire list being returned - beyond this nothing else will work if security enabled and locked down. Review instructions on security at the very top of this README.\n\n0.42-SNAPSHOT3 & SNAPSHOT2 : https://github.com/vahidhedayati/ajaxdependancyselection/issues/9\n\n0.42-SNAPSHOT1 :  https://github.com/vahidhedayati/ajaxdependancyselection/issues/8\n\n0.42-SNAPSHOT: https://github.com/vahidhedayati/ajaxdependancyselection/issues/7\n\n\n0.42 - \thttps://github.com/vahidhedayati/ajaxdependancyselection/issues/7#issuecomment-55927174 as per request - primaryList\n\t\tcan now be provided via main call i.e. controller providing the list to the taglib, domain can be set to \n\t\tan invalid value. Please refer to example6.gsp within ajaxdependancyselectexample project.\n\t\t\n\t\t\n0.41 - \tmultiple added to all select calls so multiple=true or false can be defined (optional)\n\t\tmultiple="multiple" multiple="false" multiple="true"\n\t\tfixed issue for require required - both now accepted.\n\t\t\n0.40 - \t0.39 was incomplete - a few issues with primary/secondary selection - EDIT mode. should now be fixed.\n\n0.39 -\tsecondaryValue='2' attribute added to selectPrimary/selectSecondary. Related to this question: \n\t\thttp://stackoverflow.com/questions/23220436/ajax-dependency-selection-plugin/24745037\n\t\t\n\n0.38 - \tappendName appendValue values not being passed from tagLib to services..\n\n0.37 -\tselectJs files updated logic added to if autocomp is set in \n\t\tany ads:selectPrimary/Secondary then it will look for autocompleteSecondary \n\t\ttag to fullfill autocomplete refer to selectauto3.gsp\n\t\t\n0.36 -\tminor bug in selectController '' used instead of "" for attrs.id so id was being shown as attrs.id\n \n0.35 - \tMade values updated default values optional - if appendValue is given in ads:select then it will set appendName to default value\n \t\n0.34 - \tNow supporting multiple dependency calls, in a given ads:select you can now declare upto 5 depended object bound to a\n \t\tprimary or secondary selection.\n \t\t\n0.33 - \tToo minor to mention\n0.32 - \tFurther tidyup of duplicate javascripts, cleaner calls made within taglib and reduction of duplicate gsp pages, issue\n\t\twith return results in controller displayed undefined when no results found - fixed.\n\t\t\n0.31 - \tTidyup of javascript calls within taglib, fixed secondaryNR filter2 issues - filtering now working across all select functions\n\n0.30 - \tIssues with filtering and end box with no filter not displaying values - tidyup\n\n0.29 - \tFilterDisplay and filterType intro - user override of action controllers for filtering js and controller/actions added\n\n0.28 - \tTidy up - and further work on specific filtering for selectSecondary\n\n0.27 - \tFiltering of selectPrimary\n\n0.26 - \tAdded selectAutoComplete\n\n0.23 - \tRemoved null from values updated (default additional selection field added when values update), this now means user has to \n\t\tstill choose this value\n\t\t \n0.22 - Added required by default set to required for all taglib calls. \n\n0.19 - Broken build - there were issues with the tidyup I did with selectSecondary, totally forgot it was being used by \n\t\t\tselectPrimary. 0.20 should be fine\n\n
\n

Example site:

\n

Using this plugin with the grails framework you are able to achieve this without all of the complications. Refer to this sample project which makes use of all of the examples below with some objects already pre-added to the sample projecet. Found here in this sample project:

\n

Example grails project grails 2.4.2

\n

Example grails project grails 2.5

\n

Example grails project grails 2.4.4

\n

Example grails project grails 3.0.1

\n

for grails ajaxdependancyselection plugin.Issues can be reported here. For further documentation and examples, check out the wiki

\n

I have included the text and html samples from all of the examples in the example site. Use Europe/United Kingdom/London or Oxford for a full completed example within the above example project when loading it up.

\n

General note over naming conventions.

\n

In the examples provided domainClasses has been defined as countryName cityName and so forth, this was really an example to show it can be any naming convention besides the standard id, name column naming convention. Feel free to name things as you desire i.e. this is not a requirement of the plugin.

\n

Taglibs provided:

\n
ads:selectPrimary\nads:selectSecondary\nads:selectAutoComplete\nads:autocomplete\nads:autoCompletePrimary\nads:autoCompleteSecondary\nads:selectPrimaryNR\nads:selectSecondaryNR\nads:autoCompleteSecondaryNR\nads:selectController\nads:autoCompleteHeader\n\nads:selectPrimary -  custom controller/action sample\nads:selectPrimary/Secondary Filtering\nads:selectPrimary/Secondary support for domain3 domain4 domain5 domain6 domain7 and domain8 which can all be added: \n\t\t\t\t\t\t\t-- to any selectPrimary or Secondary call, each domain is a bound object\n\t\t\t\t\t\t\t-- This means if a Country has many cities and many mayors upon country update relevant cities and mayors are loaded\n\t\t\t\t\t\t\t-- extend this now across upto domain8 for each object initiall called\n\t\t\t\t\t\t\tPlease read below on the how to and refer to the example site for a very basic demo.\n
\n

ads:selectPrimary

\n
(relationship: fully dependent ) in conjunction with ads:selectSecondary
\n
refer to above notes on jquery requirements
\n
Fully dependent domainClasses:
\n
class PrimaryDomain {\n\tString name\n\tstatic hasMany = [ secondarydomain: SecondaryDomain ]\n}\n\nclass SecondaryDomain {\n\tString name\n\tstatic belongsTo = [ primarydomain:  PrimaryDomain ]\n}\n
\n

Bindid would be:

\n
bindid="primarydomain.id"\n
\n

This you would use ads:selectPrimary the bindid is primarydomain.id the field highlighted in bold above as the bindid

\n
   <ads:selectPrimary id="MyContinent1" name="MyContinent1"\n        domain='ajaxdependancyselectexample.MyCountry'\n        searchField='countryName'\n        collectField='id'\n        \n        domain2='ajaxdependancyselectexample.MyCity'\n        bindid="mycountry.id"\n        searchField2='cityName'\n        collectField2='id'\n\n\t\t multiple='true'\n\t\t \n        noSelection="['': 'Please choose Country']" \n        setId="MyCity1"\n        value=''/>\n
\n

Entire input with explaination

\n

Now this can be either passed toa normal select or to a ads:selectSecondary where if if you have further dependency you wish to interogate.

\n

So in the case of Country city, the above is fine to call to a city select area that is a simple call like this:

\n
\t<g:select  \n\tid="MyCountry"  \n\tname="MyCity1"\n\toptionKey="id"\n\toptionValue="name" \n\tfrom="[]" \n\trequired="required" \n\tnoSelection="['': 'Please choose Country']" />\n        \n
\n

If however this was a multi nested dependency situation you could proceed to selectSecondary where this will update either a final call just like per above or call selectSecondary over and over again until nesting is completed with final select as above. again ensure you are making proper calls your optionKey and Value needs to match your own table naming convention or in simple terms

\n
<option value=YourDefindOptionKey>YourDefinedOptionValue</option>\n
\n

is what is represented on the html end

\n

ads:selectSecondary

\n
(relationship: fully dependent ) in conjunction with ads:selectPrimary
\n
refer to above notes on jquery requirements
\n

This is a tag that can be used over and over again to go through nested situations, you can also use the selectSecondaryNR features to interact from selectPrimary or selectSecondary, this will be final part of document\nBack to ads:selectSecondary example:

\n
<ads:selectSecondary id="MyCountry11" name="MyCountry11"\n    domain2='ajaxdependancyselectexample.MyCity'\n    bindid="mycountry.id"\n    searchField2='cityName'\n    collectField2='id'\n    \n    \n     appendValue=''\n     appendName='Updated'\n    \n    \n    multiple='true'\n    \n    noSelection="['': 'Please choose Continent']" \n    setId="MyCity11"\n    value="${params.MyCountry11}"/>\n
\n

ads:selectSecondary entire input and explaination

\n

##ads:selectAutoComplete

\n

This is a new feature from 0.26+, it allows you to set up a select box from which auto complete values are generated depending on what user selects.

\n
<ads:selectAutoComplete \n    id="MyContinent2" \n    id2="MyCountry2" \n    name="MyContinent2"\n    domain="ajaxdependancyselectexample.MyContinent"\n    searchField="continentName"\n    collectField="id"\n    primarybind="mycontinent.id"\n    domain2="ajaxdependancyselectexample.MyCountry"\n    searchField2="countryName"\n    collectField2="id"\n    \n    appendValue=""\n    appendName="values updated"\n    noSelection="['': 'Please choose Continent']" \n    setId="MyCountry121"\n    hidden='hidden3'\n    hidden2='hidden4'\n    value=""/>\n
\n

Explaination/example found here

\n

###ads:selectPrimary/Secondary to ads:autoCompleteSecondary\nIf you want to pass from selections to auto complete then from 0.37+ release you should be able to pass parameter autocomp="1" to any of the ads:select methods followed by a call to ads:autocompleteSecondary.. from-selection-to-autocomplete---how-to

\n

###ads:autocomplete\nThis is a simple auto complete tag lib that allows you to auto complete from a single table, refer to above notes on jquery & jquery-ui requirements

\n
<ads:autocomplete id="primarySearch" name="myId"\ndomain='ajaxdependancyselectexample.MyCountry'\nsearchField='countryName'\ncollectField='id'\nvalue=''/>\n<input type=submit value=go> </form>\n
\n

all ads:autocomplete calls

\n

###ads:autoCompletePrimary

\n
<ads:autoCompletePrimary id="primarySearch1"  \nname="NAMEOFcontinentName"\ndomain='ajaxdependancyselectexample.MyContinent'\nsearchField='continentName'\ncollectField='id'\n\nmultiple='false'\n\nsetId="secondarySearch2"\nhidden='hidden3'\nvalue=''/>\n
\n

autoCompletePrimay explained

\n

###ads:autoCompleteSecondary

\n
<ads:autoCompleteSecondary id="secondarySearch2" \nname="NAMEOFcountryName" \ndomain='ajaxdependancyselectexample.MyCountry' \nprimarybind='mycontinent.id' \nhidden='hidden3' \nhidden2='hidden4' \nmultiple='false'\nsearchField='countryName' \ncollectField='id'\nsetId="secondarySearch3" \nvalue=''/>\n
\n

autoCompleteSecondary explained

\n

###ads:selectPrimaryNR

\n
No reference mapping
\n
\tclass PrimaryDomain {\n \t\tString name\n \t\tstatic hasMany = [ secondarydomain: SecondaryDomain ]\n\t}\n\n\tclass SecondaryDomain {\n \t\tString name\n\t\tstatic belongsTo = [PrimaryDomain ]\n\t}\n
\n

Now within your call the bindid would be:

\n
bindid="secondarydomain"\n
\n

This you would use ads:selectPrimaryNR the bindid is secondarydomain the field highlighted in bold above as the bindid

\n

Notice in the PrimaryNR the bindid is the primary hasMany mapping and has no .id

\n

Example call:

\n

ads:selectPrimaryNR-Full-details

\n

###ads:selectSecondaryNR

\n

ads:selectSecondaryNR--full-details

\n

###ads:autoCompleteSecondaryNR\nads:autoCompleteSecondaryNR-full-details

\n

ads:selectController

\n
Controller action discovery, refer to above notes on jquery requirements
\n

This will display all your controllers then let you Choose available actions of this controller:\nhttps://github.com/vahidhedayati/ajaxdependancyselectexample/blob/master/grails-app/views/myContinent/example.gsp\nLine 210 onwards has an example.Typically maybe used for identifying controller name and its available actions to store against something maybe for your own custom authentication control that binds all this with something else.

\n

Here are the values explained:

\n

ads:selectController-full-details

\n

This now gets passed to a standard select call where it has an id of "ControllerActions":

\n

gccontroller-actions-or-reciever-selection-box

\n

The from on this is set to [] which gets filled in by ads:selectController setId return call.

\n

ads:autoCompleteHeader

\n
Loads in the ajaxLoader if your site is not already doing it
\n
<ads:autoCompleteHeader />\n
\n

ads:selectPrimary - Custom

\n
Customising your own calls:
\n

This is covered in the sample project labelled as custom example. Create your own controller which is set to do a custom verification:

\n
\tdef selectCountries() {\n\t\tif (params.id) {\n\t\t\tprintln params\n\t\t\tString continentName = params.searchField\n\t\t\tLong continentId = params.id as Long\n\t\t\tMyContinent continent = MyContinent.get(continentId)\n\n\t\t\t/* Either this method or below method which is much shorter\n\t\t\tdef primarySelectList = []\n\t\t\tMyCountry.findAllByMycontinentAndCountryNameLike(continent, "F%").each {\n\t\t\t\tdef primaryMap = [:]\n\t\t\t\tprimaryMap.put('id', it.id)\n\t\t\t\tprimaryMap.put('name', it.countryName)\n\t\t\t\tprimarySelectList.add(primaryMap)\n\t\t\t}\n\t\t\trender primarySelectList as JSON\n\t\t\t*/\n\t\t\t\n\t\t\t// Shorter method\n\t\t\tdef countries=MyCountry.findAllByMycontinentAndCountryNameLike(continent, "F%")\n\t\t\tdef results = countries.collect {[\t'id': it.id, 'name': it.countryName ]}.unique()\n\t\t\trender results as JSON\n\t\t}\n\t}\n\n
\n

Create a call for this:

\n
<ads:selectPrimary id="MyContinent2" name="MyContinent2"\ndomain="ajaxdependancyselectexample.MyContinent"\nsearchField="continentName"\ncollectField="id"\n\ncontroller="MyContinent"\naction="selectCountries"\n\ndomain2="ajaxdependancyselectexample.MyCountry"\nbindid="mycontinent.id"\nsearchField2="countryName"\nappendValue=""\nappendName="values updated"\ncollectField2="id"\nnoSelection="['': 'Please choose Continent']" \nsetId="MyCountry121"\nvalue=""/>\n    \n    \n    \n<g:select name="MyCountry" id="MyCountry121"  from="[]" required="required" \nnoSelection="['': 'Please choose Continent']" />\n
\n

I will be updating this so that less input is required when custom action controller is defined.

\n

ads:selectPrimary/Secondary Filtering

\n
Filtering can be hard coded per select call or can be left for the user to filter output of a selectbox. this can be either useful if you only want to show specific results from selection for specific user or possibly when you wish user to speed up selection process and let them control the output of the selectbox.
\n

Most basic example is a hard coded version: /ajaxdependancyselectionexample/myContinent/norefselectSecondaryFilteringFixed.gsp and or https://github.com/vahidhedayati/ajaxdependancyselection/wiki/Nested-Selection-from-fully-fixed-search-all-that-way-including-a-secondaryNR

\n

This is where you start with your <ads:selectPrimary filter="something" filter2="another"\nThis will now filter results for primary matching against something and the next secondary call to filter against another

\n

On your next <ads:selectSeconday you simply call filter2="somethingelse"

\n

This will now pass this filter to next object being completed and all the way to last standard call which will end in standard <g:select box but will still be filtered.

\n

The other way is to enable filtering and let user control the filter, to do this simply switch filter="_ON" in each <ads:selectPrimary/Secondary call

\n

In primary it is just as simple as switching it on, within secondary calls it gets a little more complex.

\n
Primary & PrimaryNR in full:
\n

To enable user driver filtering - add this

\n
filter="_ON"\nhidden="hiddenFieldForPrimary"\n
\n

To enable hard coded filtering add this:

\n
filter="SOMETHING"\n
\n

With either a fixed filter above or dynamic user controlled followed by: Only needed if you want to define you next select filter physically

\n
filter2="B"\t\t\t\t\t\n
\n

Optional stuff:\t\nput this in so with filtering no results are shown if user does not match or as it starts and only show matching results in select to what user inputs

\n
filterDisplay="none" \t\t\t\n
\n

Values are : S E A - Start of Record End of Record or by default if not defined Any part of record i.e. wild card search.

\n
filterType ="A" \t\t\t\n
\n

Override optional stuff:

\n

if you wish to point the filtering actions to another location at the moment default autoComplete controller from plugin

\n
filterController="YourController" \t\n
\n

if you wish to define your own action for the above controller call

\n
filteraction="your action"\n
\n

Default is loadFilterWord this loads up the user input box for end user filtering

\n
filteraction="loadFilterWord"\n\n
\n

The action that returns the primary list the default value is as defined

\n
filteraction2="returnPrimarySearch"\n\n
\n

Config.groovy overrides:

\n
ajaxdependancyselection.filterField='/autoComplete/filterField'\najaxdependancyselection.selectBasicJS='/autoComplete/selectJs'\n
\n
Secondary & Secondary NR in full:
\n

To enable user driver filtering - add this

\n
filter="_ON"\nhidden="hiddenFieldForPrimary"\n
\n

To enable hard coded filtering for the next field add this: Only needed if you want to define you next select filter physically

\n
filter2="SOMETHING"\t\t\t\t\t\t\t\n
\n

Optional stuff: put this in so with filtering no results are shown if user does not match or as it starts and only show matching results in

\n
filterDisplay="none"\t\t\n
\n

select to what user inputs: Values are : S E A - Start of Record End of Record or by default if not defined Any part of record i.e. wild card search.

\n
filterType ="A" \t\t\t\n
\n

Override optional stuff:

\n

If you wish to point the filtering actions to another location at the moment default autoComplete controller from plugin

\n
filterController="YourController" \t\n
\n

If you wish to define your own action for the above controller call

\n
filteraction="your action"\t\t\t\t\t\t\t\t\n
\n

Default is loadFilterWord this loads up the user input box for end user filtering

\n
filteraction="loadFilterWord2"\t\t\n
\n

The action that returns the secondary search whilst filter results

\n
filteraction2="secondarySearch"\t\t\n
\n

Config.groovy overrides:

\n
ajaxdependancyselection.filterField='/autoComplete/filterField'\najaxdependancyselection.selectSecondaryJsFilter='/autoComplete/selectJs1'  {Secondary default}\najaxdependancyselection.selectSecondaryJsFilter='/autoComplete/selectJsNr1'  {SecondaryNR default}\n
\n

For other examples of filtering, check out or the filtering example page within the example project site.

\n

ads:selectPrimary/Secondary Multi domainClass loading:

\n
Feature since 0.34
\n

This allows you to load up domain3, domain4, domain5, domain6, domain7, domain8 per Primary or Secondary Call.\nEach of them can then have the same nesting meaning some wild dependencies can be created and complex selecting provided.

\n

The how to:

\n
<ads:selectPrimary id="MyDepartments" name="MyDepartments"\ndomain='ajaxdependancyselectexample.Departments'\nsearchField='name'\ncollectField='id'\nnoSelection="['': 'Please choose Department']" \n\ndomain2='ajaxdependancyselectexample.Employee'\nbindid="department.id"\nsearchField2='name'\ncollectField2='id'\nsetId="employeeID"\n\n\ndomain3='ajaxdependancyselectexample.Documents'\nbindid3="department.id"\nsearchField3='name'\ncollectField3='id'\nsetId3="documentsId"\nfilter3="L"\n\nvalue=''/>\n\n<g:select name="employee" id="employeeID" optionKey="id" optionValue="name" from="[]" \nrequired="required" noSelection="['': 'Please choose department']" />\n\n<g:select name="document" id="documentsId" optionKey="id" optionValue="name" from="[]" \nrequired="required" noSelection="['': 'Please choose department']" />\n
\n

The Primary block or Secondary Block simply create a new element that kind of follows the domain2 object\nbut in short everything ends with the correct numbering sequence. As you can see the bindings employeeID and documentsId got updated with relevant values that were depedent upong primary selection.

\n

Take a look at the multidomain example in the wiki or within the example project where it covers:

\n
Example1: Simple multi domain dependency call one object two dependencies with filtering on one of the calls
\n
Example2: Simple multi domain dependency call one object two dependencies with no filtering
\n
Example3: Multi domain dependency call to domain3 and domain4
\n
Example4: Multi domain dependency call to domain3 and domain4 with domain4 then having its own multi depenency relatiobship
\n

This last example shown here:

\n

Please note only the first computer from each initial department selected has any further values.

\n
<form method=post action=example5>\n\n<ads:selectPrimary id="MyDepartments141" name="MyDepartments141"\ndomain='ajaxdependancyselectexample.Departments'\nsearchField='name'\ncollectField='id'\nnoSelection="['': 'Please choose Department']" \n\ndomain2='ajaxdependancyselectexample.Employee'\nbindid="department.id"\nsearchField2='name'\ncollectField2='id'\nsetId="employeeID141"\n\ndomain3='ajaxdependancyselectexample.Documents'\nbindid3="department.id"\nsearchField3='name'\ncollectField3='id'\nsetId3="documentsId141"\n\ndomain4='ajaxdependancyselectexample.Computers'\nbindid4="department.id"\nsearchField4='pcName'\ncollectField4='id'\nsetId4="computersId141"\nvalue=''/>\n\n<g:select name="employee" id="employeeID141" optionKey="id" optionValue="name" from="[]" \nrequired="required" noSelection="['': 'Please choose department']" />\n<g:select name="document" id="documentsId141" optionKey="id" optionValue="name" from="[]" \nrequired="required" noSelection="['': 'Please choose department']" />\n\n\n\n<ads:selectSecondary id="computersId141" name="computersId141"\n\ndomain2='ajaxdependancyselectexample.Os'\nbindid="computers.id"\nsearchField2='osName'\ncollectField2='id'\nsetId="Os13"\n\ndomain3='ajaxdependancyselectexample.Users'\nbindid3="computers.id"\nsearchField3='userName'\ncollectField3='id'\nsetId3="userId13"\n\nappendValue=''\nappendName='Updated'\n\nnoSelection="['': 'Please choose Department']" \n\nvalue="${params.computersId141}"/>\n\n\n<g:select name="Os" id="Os13" optionKey="id" optionValue="pcName" from="[]" \nrequired="required" noSelection="['': 'Please choose Computer']" />\n\n<g:select name="users" id="userId13" optionKey="id" optionValue="userName" \nfrom="[]" required="required" noSelection="['': 'Please choose computer']" />\n\n<input type=submit value=go>\n</form>\n\t\t\n
\n

0.40+ Edit an existing page using ajaxdependancyselection.

\n

This may be rather difficult but if the values are then stored on DB and you wish to further edit the defined stored values you now can from version 0.40+.\nPlease refer to https://github.com/vahidhedayati/ajaxdependancyselectexample/blob/master/grails-app/views/myContinent/testedit.gsp. This page has fixed values defined with an additional variable defined within selectPrimary/Secondary:

\n
value='2'\nsecondaryValue='2'\n
\n

Although in the given gsp example page the values are hardcoded, in real life those be the values returned from db

\n
value="${mydomainClass.primaryValue}"\nsecondaryValue="${mydomainClass.secondaryValue}"\n
\n

So in selectPrimary/selectSecondary you define both the value and secondaryValue and the plugin will assign them to the relevant boxes. please follow the example to get an idea

\n

END OF MAIN DOCUMENTATION

\n

--------------------------

\n
Further Examples below
\n

Example no reference domain classes:

\n

Here are two domain classes with a no reference set up and require ads:selectSecondaryNR feature:

\n
class MyCity {\nString cityName\n  MyCountry mycountry\n  static hasMany=[myborough: MyBorough]\n  String toString()  { "${cityName}"}\n}\n\nclass MyBorough {\n  String actualName\n  static belongsTo = [MyCity]\n  String toString() { "${actualName}" }\n}\n\n
\n

Examples of primary to secondary then to seoncdaryNR

\n

This non working gsp has some examples: https://github.com/vahidhedayati/ajaxdependancyselectexample/blob/master/grails-app/views/myContinent/noRefAutoComplete.gsp

\n

Here is the GSP making a nested call where an element has a no reference relationship, the gsp page in the example called norefselectionext.gsp goes back out of a NR relationship and calls Streets domain after borough to then load up a further relationsip

\n

select-primary-to-secondary-then-to-seoncdaryNR-nested-call

\n

Examples Auto Complete Secondary to secondaryNR

\n

This non working gsp has some examples

\n

autocomplete-primary-to-secondary-to-secondaryNR-nested-call

\n

Thanks for contributions from

\n

Alidad's CountryCityAutoComplete project which inspired this plugin.

\n

Burt Beckwith for helping clean up the code.

\n

Domurtag for identifying and helping improve plugin documentation and features.

\n" }, { "bintrayPackage": { "name": "alexa-skills", "repo": "alexa-skills", "owner": "rvanderwerf", "desc": "This is a Grails 3.x plugin to help make Amazon Alexa Skills / Speechlets", "labels": [ "amazon", "alexa" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "", "latestVersion": "0.1.2", "updated": "2017-11-07T07:29:01.366Z", "systemIds": [ "org.grails.plugins:alexa-skills" ], "vcsUrl": "https://github.com/rvanderwerf/grails-alexa-skills" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

This is the Alexa skills Plugin!

\n

This plugin helps you create Speechlets/Skills on Grails. It will create a starter class for you\nso you can get running quickly making your own skills.

\n

Installation

\n

add the following to the dependencies {} block to your build.gradle:

\n
dependencies {\n     compile "org.grails.plugins:alexa-skills:0.1.2"\n}\n
\n

also if you have issues resolving the plugin, try adding my bintray repo (NOT to buildscript block but the lower one):

\n
\nrepositories {\n    maven { url  "http://dl.bintray.com/rvanderwerf/alexa-skills" }\n    maven {\n            url  "http://dl.bintray.com/vanderfox/alexa-skills-kit-java" \n    }\n}\n\n\n
\n

How it works

\n

run 'grails create-speechlet '\nThis will create a speechlet class file located in grails-app/speechlets. Do not use the suffix 'Speechlet' because that will be automatically appended to the name.

\n

Configuration

\n

Here's the config values you can set in application.yml or application.groovy:

\n

alexaSkills.supportedApplicationIds (String)

\n\n

alexaSkills.disableVerificationCheck (boolean)

\n\n

alexaSkills.serializeRequests (boolean)

\n\n

alexaSkills.serializeRequestsOutputPath (boolean)

\n\n

Recommended usage with a Controller

\n
class TestController {\n\n    def speechletService\n    def testSpeechlet\n\n\n    def index() {\n        speechletService.doSpeechlet(request,response, testSpeechlet)\n    }\n\n}\n
\n

Here you see the speechlet is turned into a Spring bean, and you invoke the speechlet service and pass it in.\nLikely we could turn the speechlet artefact class into a controller itself in the future to skip this.\nIf you are using Spring security, make sure to whitelist the urlmapping for the index.

\n

Blog Article from Grails Team Blog on how to make this all work

\n

Introduction

\n\n

Recently I gave a talk at GR8Conf.eu about building applications for the Amazon Alexa platform. I talked about using Groovy\nwith Lambdas to demonstrate Skills (Alexa Apps) as well as using Grails. I'll give this talk again at GR8Conf.us at the end of\nJuly and have even more good stuff to show. On top of that, after working on this for months I have the material to have an\nAlexa workshop at GR8Conf.us(Thanks to Collin Harrington for helping with the idea). Good Times! I wanted to write a post as a step-by step on using a plugin I've recently developed\nas to help you crank out Alexa apps(skills or speechlets). Amazon has a promotion right now, if you submit a new skill to their library,\nyou can win a free T-Shirt, so maybe you can make something cool with this and get one! You do not even need an Amazon device: you\ncan point your browser to https://echosim.io to use their emulator.

\n

Let me first get started to explain how these things work and a little about the devices. Starting a couple years ago, Amazon released\na home device/speaker thing called the Echo. It's a household helper device with very nice multi-directional microphones, and a nice speaker\nfor playing music. At first I didn't get one or understand it: it sounded like a useless toy to me. However peers gobbled them up and\nstarted playing around with them. They weren't building apps for it, but raved about how cool it was and how it helped automate their\nhome and do useful things. Then they started saying they loved it so much they were buying more units and putting them all over their house.\nNow my attention was had - of course the first thing that pops into my head was 'how can I get Groovy to work with this thing?'

\n\n

The first examples they give are all about AWS Lambda functions in Node - however they aren't fantastic on Java because they have a hard limit of 50mb\njars you can upload. Surely you can't fit all of grails and dependencies in there to do much. Still we gave it a shot - I followed\nBenoit H\ufffd\ufffd\ufffd\ufffddiard's presentation on Groovy with Lambdas from GGX 2015. I sat down with a buddy of mine, Lee Fox (He will be at GR8Conf.us), and we hammed out a bunch of ideas\nwe could build with it - in Groovy of course!

\n

The first app we got working was a simple Twitter app that combined Groovy, Spring Social and Skills to make a skill that would connect to\nTwitter and search for tweets, as well as give updates to your timeline. You can find the code here. Good! Now we're getting somewhere. I did a little digging and found\nthey have some servlet support to make a stand along web service - now we can get Grails involved and make this less hideous.

\n

Next we took it a level up - we didn't want the user to have to hard-code their twitter API keys to run the app, and you can't publish a skill that\npulls down someone else's twitter info. So we build a Grails app that used Spring Security, Oath plugin, and Spring Security UI to allow a UI\nthat lets you register and enter your own twitter keys for your account. Source for that is here.

\n

After that it was time to make a plugin to help you make these skills - that I published while I was out at GR8Conf.eu here.\nIt works similar to the Quartz plugin in that you have a CLI command to create a working template of a Skill to get you started. I will show you here how to build\na skill using the Grails plugin to get you started making your own Skills in a short about of time.

\n

How Alexa service Works

\n

The devices themselves, (which are currently the Echo, Tap, Dot, and FireTV) don't do a whole lot. They even publish the source to the devices\nfor you to look at if you choose here. The magic resides on the amazon side that handles all the voice recognition and handling of requests.\nBasically what happens is the user initiates a action (skill) on the device, and it goes to the alexa service to figure out what you want to do.\nWhen your app is invoked, it calls back to your app via a JSON HTTPS call and initiates a series of Intents to make your app do things. Your app simple waits for the call\nand takes appropriate action (via JSON) to do what you want. It's up to you as the developer to make it do something useful.

\n\n

The picture above give you an idea of how it works (from Amazon's site). Let's go over Intents and Sample utterances to have a better idea of what's going on.

\n

Intents

\n

Intents are sort of like simplified Intents on android if you have every done Android coding. They signal an intention for a command to run to do something.

\n

Let's look at an example one to get an idea:

\n
{\n  "intents": [\n    {\n      "intent": "ResponseIntent",\n      "slots": [\n        {\n          "name": "Answer",\n          "type": "AMAZON.LITERAL"\n        }\n      ]\n    },\n    {\n      "intent": "QuestionCountIntent",\n      "slots": [\n        {\n          "name": "Count",\n          "type": "AMAZON.NUMBER"\n        }\n      ]\n    },\n    {\n      "intent": "AMAZON.HelpIntent"\n    }\n  ]\n}\n
\n

Here this application can trigger 3 intents: ResponseIntent, QuestionCountIntent, and HelpIntent. You use JSON to tell it what these are.\nYou can define 'slots' which is the expected responses which are comprised of a name and Type. There are pre-defined data types you can use\nto help amazon parse what is said (Number for example knows the user is going to say a number. Literal is a simple String. Some intents don't need anything\nas they are 'built in' like the help intent (no inputs).

\n

A little bit about slots - they are entirely optional. You can do things like define a list of allowed responses (custom slots) that are valid things for the user to say.\nIn this case the ResponseIntent is free form, and we sort out what we want to do by parsing the string we get from Amazon (translated via TTS).

\n

Sample Utterances

\n

Let's look at another example:

\n
ResponseIntent {test|Answer}\nResponseIntent {last player|Answer}\nResponseIntent {test test|Answer}\nResponseIntent {test test test|Answer}\nResponseIntent {test test test test|Answer}\nQuestionCountIntent {Count} questions\n
\n

Here we see the intent each utterances (what the person says) and map it to an intent. Amazon will generate common words like conjunctions and ignored things on their\nend so you don't have to mess with handling things like 'and', 'the', 'or' etc. Variables are surrounded by {}. You can use the | operator to specify alternate options.\nIf you want to say something to your skill, it must match the pattern here. For this case, we want to parse multi-world answers to a question.\nBasically here we support one, two, three of four word responses - anything else will be cut off/ignored. The last item allows the user to answer how many questions they want to be asked.

\n

Requirements

\n\n

Let's make a Grails app using the plugin and I will explain more as we go

\n

The plugin is for Grails 3.x only. Let's create a new app first:

\n
grails create-app skillsTest\n
\n

Now lets open build.gradle and add the plugin into the dependencies {} closure:

\n
compile "org.grails.plugins:alexa-skills:0.1.1"\n
\n

Now let's create a skill from the command line:

\n
grails create-speechlet SkillsTest\n| Rendered template Speechlet.groovy to destination grails-app/speechlets/skillstest/SkillsTestSpeechlet.groovy\n
\n

Now let's see what it's created in grails-app/speechlets:

\n
\n@Slf4j\nclass SkillsTestSpeechlet implements GrailsConfigurationAware, Speechlet {\n\n    def grailsApplication\n\n    Config grailsConfig\n    def speechletService\n\n\n    def index() {\n        speechletService.doSpeechlet(request,response, this)\n    }\n\n    /**\n     * This is called when the session is started\n     * Add an initialization setup for the session here\n     * @param request SessionStartedRequest\n     * @param session Session\n     * @throws SpeechletException\n     */\n    public void onSessionStarted(final SessionStartedRequest request, final Session session)\n            throws SpeechletException {\n        log.info("onSessionStarted requestId={}, sessionId={}", request.getRequestId(),\n                session.getSessionId())\n\n    }\n\n    /**\n     * This is called when the skill/speechlet is launched on Alexa\n     * @param request LaunchRequest\n     * @param session Session\n     * @return\n     * @throws SpeechletException\n     */\n    public SpeechletResponse onLaunch(final LaunchRequest request, final Session session)\n            throws SpeechletException {\n        log.info("onLaunch requestId={}, sessionId={}", request.getRequestId(),\n                session.getSessionId())\n\n        return getWelcomeResponse()\n    }\n\n    /**\n     * This is the method fired when an intent is called\n     *\n     * @param request IntentRequest intent called from Alexa\n     * @param session Session\n     * @return SpeechletResponse tell or ask type\n     * @throws SpeechletException\n     */\n    public SpeechletResponse onIntent(final IntentRequest request, final Session session)\n            throws SpeechletException {\n        log.info("onIntent requestId={}, sessionId={}", request.getRequestId(),\n                session.getSessionId())\n\n        log.debug("invoking intent:${intentName}")\n        PlainTextOutputSpeech speech = new PlainTextOutputSpeech()\n        // Create the Simple card content.\n        SimpleCard card = new SimpleCard(title:"Twitter Search Results")\n        def speechText = "I will say something"\n        def cardText = "I will print something"\n        // Create the plain text output.\n        speech.setText(speechText)\n        card.setContent(cardText)\n        SpeechletResponse.newTellResponse(speech, card)\n\n    }\n    /**\n     * Grails config is injected here for configuration of your speechlet\n     * @param co Config\n     */\n    void setConfiguration(Config co) {\n        this.grailsConfig = co\n    }\n\n    /**\n     * this is where you do session cleanup\n     * @param request SessionEndedRequest\n     * @param session\n     * @throws SpeechletException\n     */\n    public void onSessionEnded(final SessionEndedRequest request, final Session session)\n            throws SpeechletException {\n        log.info("onSessionEnded requestId={}, sessionId={}", request.getRequestId(),\n                session.getSessionId())\n        // any cleanup logic goes here\n    }\n\n    SpeechletResponse getWelcomeResponse()  {\n        String speechText = "Say something when the skill starts"\n\n        // Create the Simple card content.\n        SimpleCard card = new SimpleCard(title: "YourWelcomeCardTitle", content: speechText)\n\n        // Create the plain text output.\n        PlainTextOutputSpeech speech = new PlainTextOutputSpeech(text:speechText)\n\n        // Create reprompt\n        Reprompt reprompt = new Reprompt(outputSpeech: speech)\n\n        SpeechletResponse.newAskResponse(speech, reprompt, card)\n    }\n\n    /**\n     * default responder when a help intent is launched on how to use your speechlet\n     * @return\n     */\n    SpeechletResponse getHelpResponse() {\n        String speechText = "Say something when the skill need help"\n        // Create the Simple card content.\n        SimpleCard card = new SimpleCard(title:"YourHelpCardTitle",\n                content:speechText)\n        // Create the plain text output.\n        PlainTextOutputSpeech speech = new PlainTextOutputSpeech(text:speechText)\n        // Create reprompt\n        Reprompt reprompt = new Reprompt(outputSpeech: speech)\n        SpeechletResponse.newAskResponse(speech, reprompt, card)\n    }\n\n    /**\n     * if you are using account linking, this is used to send a card with a link to your app to get started\n     * @param session\n     * @return\n     */\n    SpeechletResponse createLinkCard(Session session) {\n\n        String speechText = "Please use the alexa app to link account."\n        // Create the Simple card content.\n        LinkAccountCard card = new LinkAccountCard()\n        // Create the plain text output.\n        PlainTextOutputSpeech speech = new PlainTextOutputSpeech(text:speechText)\n        log.debug("Session ID=${session.sessionId}")\n        // Create reprompt\n        Reprompt reprompt = new Reprompt(outputSpeech: speech)\n        SpeechletResponse.newTellResponse(speech, card)\n    }\n\n}\n\n
\n

Also the plugin will generate a Controller class embedded in your Speechlet file. If you are using Spring Security, you will want to make sure that uri is\nassessable to the outside to the Alexa service can contact it (there are some requirements I'll fill you in on later):

\n
\n/**\n * this controller handles incoming requests - be sure to white list it with SpringSecurity\n * or whatever you are using\n */\n@Controller\nclass SkillsTestController {\n\n    def speechletService\n    def skillsTestSpeechlet\n\n\n    def index() {\n        speechletService.doSpeechlet(request,response, skillsTestSpeechlet)\n    }\n\n}\n\n
\n

The speechlet artefact will be registered as a Spring bean so it's automatically injected. There is also a service the plugin provides to handle the boring\nstuff like verifying the request, checking the app ID (more on that later) and the plumbing that calls your skill.

\n

Built-in Events

\n

Looking at the code example above, you can see it made several methods for you. These are part of the skill(speechlet) lifecycle.\nThe first one is:

\n

onSessionStarted

\n

This allows you to store variables for the duration of the session (the interactions as a whole of the app for that time). You can do\nsome setup here and store variables you can use later. This is technically optional for you to implement.

\n

onLaunch

\n

This is called when you invoke the skill. When you say 'Alexa open skillTest' etc this is you chance to say an opening message about your app, what it does, or what they will\nneed to do.

\n

onIntent

\n

This is the meat and is required to be implemented. When your sample utterances maps to an Intent when the user says something this is invoked.\nHere you should generate a card that will appear in the Alexa app on your phone (you can also get to this on your local network via browser by going to 'echo.amazon.com'.\nCards are similar to Android cards (more popular in Android Wear) that simply show a message to the user they can see what is going on. You can make several kinds\nof cards which are Simple, Standard, and LinkAccount. Here we have a switch statement to figure out what Intent to process and call the code for the appropriate intent.

\n

onSessionEnded

\n

This is the last one, optional, where you can clean up and session resources you might have created like database records for the run.

\n

I've added a few other helper methods to see how to render a help response, link an account, and get some setup details from the Grails config. As a first pass, just try to get the default template working, then start to change things like changing the text, add an Intent, etc.

\n

Set up your app on Amazon Developer Portal

\n

This is separate from AWS. I am not aware of any APIs that will create all of this for you so you have to sign up for an account and do this by hand for each skill you want to run.

\n\n\n\n\n\n\n\n\n\n\n

Now note the application ID it gives you. You will need to add this to the application.groovy/yml file so the application will know the app ID and accept it.

\n

Copy the application ID on the first tab 'SKILL INFORMATION', and paste that into application.groovy

\n
alexaSkills.supportedApplicationIds="amzn1.echo-api.request.8bd8f02f-5b71-4404-a121-1b0385e56123,amzn1.echo-sdk-ams.app.84d004e5-e084-4087-a8c3-a80b12fd2009,amzn1.echo-sdk-ams.app.dc1dea0e-ab91-446d-a1c7-460df5e83489"\nalexaSkills.disableVerificationCheck = true // helpful for debugging or replay a command via curl\nalexaSkills.serializeRequests = true // this logs the requests to disk to help you debug\nalexaSkills.serializeRequestsOutputPath = "/tmp/"\n
\n

Build and deploy your war file to your server (btw it must be port 443 HTTPS, no exceptions)

\n

Test your app

\n

Now try it on your Echo/Alexa device. Say either 'start' or 'open' and the invocation name you gave the app and follow the prompts! You can also use the test function on the portal itself.

\n

Debugging

\n

Debugging can be very frustrating. Make sure to turn your log level to debug. In the Grails config, the there is an option called 'serializeRequests' and a output path for them.\nThis allows you to capture the request that came from Amazon. If you are trying to test a fix for a bug, you can replay this via CURL. The files will look like this:

\n
-rw-r--r-- 1 tomcat tomcat      598 Jun  6 22:45 speechlet-1465249551692.out\n-rw-r--r-- 1 tomcat tomcat      636 Jun  6 22:45 speechlet-1465249557538.out\n-rw-r--r-- 1 tomcat tomcat      598 Jun  6 22:46 speechlet-1465249601675.out\n-rw-r--r-- 1 tomcat tomcat      636 Jun  6 22:46 speechlet-1465249607216.out\n
\n

The build-in security provided by the plugin and underlying library will now allow you to reuse a request because the hash ahd timestamps are too old (to prevent this type of attack called a 'replay attack'). You can disable this check for dev purposes with the 'disableVerificationCheck' Grails config value.\nNow you can replay a file via CURL back to your server to avoid the whole voice interaction to test that one case (and test it locally!):

\n
curl -vX POST http://localhost:8080/test/index -d @speechlet-14641464378122470.out --header "Content-Type: application/json"\n
\n

If you save enough requests of a normal interaction, you could write some functional tests that replay this as part of a test suite or just be able to dev against them locally a bit.

\n

Advanced stuff - full UI with Spring Security, OAuth

\n

If your want a UI for the user and use account linking, an easy path is to add Spring Security, Spring Security UI, Spring Security OAuth grails plugins.\nYou can see an example of how to do this here.

\n

Advanced stuff - say sample audio clips in your skill

\n

There is a supported markup called SSML which allows up to 90 seconds of low quality mp3 sound clips to play. Their settings/requirements are quick picky to work:

\n\n

Example SSML:

\n
    <speak>\n      <audio src="\\"https://s3.amazonaws.com/vanderfox-sounds/groovybaby1.mp3\\"/"> ${speechText}\n      </audio>\n    </speak>\n
\n

Useful links

\n\n
\n

Conclusion

\n

The Alexa service is a great invention that is catching on. Google and Apple are dipping their toes into the market. I see the star trek experience in the home\nbeing a reality for everyone in a few years. Already my wife uses it (who swore she never would), and my 4 year old asks it to tell her jokes all the time. I use it to control my lights very often. The sky is the limit, and these tools can be useful in the workplace too. Get out there and build some neat stuff for Alexa with Grails!

\n" }, { "bintrayPackage": { "name": "angular-annotate-asset-pipeline", "repo": "asset-pipeline", "owner": "craigburke", "desc": "AngularJS Annotate for Asset Pipeline 2.0+", "labels": [ "angular-1" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/craigburke/angular-annotate-asset-pipeline/issues", "latestVersion": "2.4.1", "updated": "2016-05-13T16:12:37.000Z", "systemIds": [ "com.craigburke.angular:angular-annotate-asset-pipeline" ], "vcsUrl": "https://github.com/craigburke/angular-annotate-asset-pipeline" }, "documentationUrl": null, "mavenMetadataUrl": "https://repo1.maven.org/maven2/com/craigburke/angular/angular-annotate-asset-pipeline/maven-metadata.xml", "readme": null }, { "bintrayPackage": { "name": "angular-scaffolding", "repo": "plugins", "owner": "grails", "desc": "Provides scaffolding for AngularJS 1.x applications", "labels": [ "angular-1" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails/grails-angular-scaffolding/issues", "latestVersion": "2.0.1", "updated": "2023-03-07T06:34:49.000Z", "systemIds": [ "org.grails.plugins:angular-scaffolding" ], "vcsUrl": "https://github.com/grails/grails-angular-scaffolding" }, "documentationUrl": "https://grails.github.io/grails-angular-scaffolding/", "mavenMetadataUrl": "https://repo1.maven.org/maven2/org/grails/plugins/angular-scaffolding/maven-metadata.xml", "readme": null }, { "bintrayPackage": { "name": "angular-template-asset-pipeline", "repo": "asset-pipeline", "owner": "craigburke", "desc": "AngularJS Templates for Asset Pipeline 2.0+", "labels": [ "angular-1", "asset-pipeline" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/craigburke/angular-template-asset-pipeline/issues", "latestVersion": "2.4.0", "updated": "2017-07-03T19:47:23.923Z", "systemIds": [ "com.craigburke.angular:angular-template-asset-pipeline" ], "vcsUrl": "https://github.com/craigburke/angular-template-asset-pipeline" }, "documentationUrl": null, "mavenMetadataUrl": "https://repo1.maven.org/maven2/com/craigburke/angular/angular-template-asset-pipeline/maven-metadata.xml", "readme": null }, { "bintrayPackage": { "name": "angular2-scaffolding", "repo": "plugins", "owner": "grails", "desc": "Provides scaffolding for Angular 2 applications", "labels": [ "angular-2" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails-plugins/grails-angular2-scaffolding/issues", "latestVersion": "1.0.0.RC1", "updated": "2017-03-27T17:02:14.861Z", "systemIds": [ "org.grails.plugins:angular2-scaffolding" ], "vcsUrl": "https://github.com/grails-plugins/grails-angular2-scaffolding" }, "documentationUrl": "https://grails-plugins.github.io/grails-angular-scaffolding/latest/", "mavenMetadataUrl": null, "readme": "

Grails 3 Angular Scaffolding Plugin

\n

\"Build

\n

A plugin for generating client side assets based on domain classes

\n

Documentation

\n

Latest: https://grails-plugins.github.io/grails-angular-scaffolding/latest\nSnapshot: https://grails-plugins.github.io/grails-angular-scaffolding/snapshot

\n" }, { "bintrayPackage": { "name": "angularjs-scaffolding", "repo": "plugins", "owner": "grails", "desc": "Provides scaffolding for AngularJS 1.x applications", "labels": [ "angular-1" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails-plugins/grails-angularjs-scaffolding/issues", "latestVersion": "1.0.3", "updated": "2017-04-11T14:05:27.613Z", "systemIds": [ "org.grails.plugins:angularjs-scaffolding" ], "vcsUrl": "https://github.com/grails-plugins/grails-angularjs-scaffolding" }, "documentationUrl": "https://grails-plugins.github.io/grails-angularjs-scaffolding/latest/", "mavenMetadataUrl": null, "readme": "

Grails 3 AngularJS Scaffolding Plugin

\n

\"Build

\n

A plugin for generating client side assets based on domain classes

\n

Documentation

\n

http://grails-plugins.github.io/grails-angularjs-scaffolding/latest

\n" }, { "deprecated": "Source repository is archived and no Grails >= 3 plugin library published. This entry should probably be removed from the registry.", "bintrayPackage": { "name": "anthofo.plugins:json-annotations-marshaller", "repo": "plugins", "owner": "anthofo", "desc": "Grails json-annotations-marshaller plugin", "labels": [ "json" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/anthofo/grails3-json-annotations-marshaller/issues", "latestVersion": "1.0", "updated": "2016-03-31T16:14:33.462Z", "systemIds": [ ], "vcsUrl": "https://github.com/anthofo/grails3-json-annotations-marshaller" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

json-apis

\n

Grails plugin for managing multiple JSON apis using domain class annotations

\n

The goal of this plugin is to help convert Grails domain classes into various\nJSON representations needed in different parts of your web application or to\nsupport various API versions.

\n

Features:

\n\n

Example of use

\n

Several API variants can be easily defined in domain classes by annotating properties with\nJsonApi and providing a list of API profile names under which that property should appear in the\nresulting JSON. Marking a property with the JsonApi annotation but providing no API names will\ninclude that property in all APIs. The database identity property will always be included\nautomatically. One could for instance define the following domain class:

\n
import grails.plugins.jsonapis.JsonApi\n\nclass User {\n\t@JsonApi\n\tString screenName\n\n\t@JsonApi('userSettings')\n\tString email\n\n\t@JsonApi(['userSettings', 'detailedInformation'])\n\tString twitterUsername\n}\n
\n

Then in the controller one would call the desired named JsonApi configuration to get only\nthe fields defined for that API. The following code:

\n
JSON.use("detailedInformation")\nrender person as JSON\n
\n

...would convert the person object into JSON containing the id, screenName and twitterUsername\nproperties but not the email. It works for collections as well, converting each collection\nmember using the same API profile that was used to convert the parent:

\n
static hasMany = [\n\tpets: Pet\n]\n@JsonApi('detailedInformation')\nSet pets\n
\n

To include a domain object's parent in a JSON API, declare a belongsTo property explicitly\nand annotate it with JsonApi (but be careful not to create circular paths by including both\nends of a belongsTo/hasMany pair):

\n
static belongsTo = [\n\tuser:User\n]\n\n@JsonApi('petDetails') \nUser user\n
\n

JSONBuilder is supported, too:

\n
JSON.use("userSettings")\nrender(contentType: "text/json") {\n    user = User.first()\n    pet = Pet.first()\n}\n
\n

Future plans

\n\n" }, { "bintrayPackage": { "name": "application-config", "repo": "plugins", "owner": "neilab", "desc": "Allows external configuration via grails.config.locations, JNDI, and system properties", "labels": [ "config" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/neilabdev/application-config/issues", "latestVersion": "1.1.3", "updated": "2018-08-08T12:58:00.158Z", "systemIds": [ "com.neilab.plugins:application-config" ], "vcsUrl": "https://github.com/neilabdev/application-config" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Application-Config

\n

\"Build

\n

This plugin based on the amazing work started in plugin external-config by Sudhir Nimavat and Dennie de Lange,\nwhich mimiced the Grails 2 way of handling external configurations defined in grails.config.locations; with the necessary additions to allow configurations via command line, system properties, and JNDI.

\n

Contributors

\n\n

Installation

\n

Add dependency to your build.gradle:

\n
dependencies {\n    compile 'com.neilab.plugins:application-config:1.1.3'\n}\n
\n

Usage

\n

When you add this plugin to your Grails build, it will automatically look for the property grails.config.locations. Define this in in either application.yml like this:

\n
grails:\n    config:\n        locations:\n            - classpath:myconfig.groovy\n            - classpath:myconfig.yml\n            - classpath:myconfig.properties\n            - file:///etc/app/myconfig.groovy\n            - file:///etc/app/myconfig.yml\n            - file:///etc/app/myconfig.properties\n            - ~/.grails/myconfig.groovy\n            - ~/.grails/myconfig.yml\n            - ~/.grails/myconfig.properties\n            - file:${catalina.base}/myconfig.groovy\n            - file:${catalina.base}/myconfig.yml\n            - file:${catalina.base}/myconfig.properties\n
\n

or in application.groovy like this:

\n
grails.config.locations = [\n        "classpath:myconfig.groovy",\n        "classpath:myconfig.yml",\n        "classpath:myconfig.properties",\n        "file:///etc/app/myconfig.groovy",\n        "file:///etc/app/myconfig.yml",\n        "file:///etc/app/myconfig.properties",\n        "~/.grails/myconfig.groovy",\n        "~/.grails/myconfig.yml",\n        "~/.grails/myconfig.properties",\n        'file:${catalina.base}/myconfig.groovy',\n        'file:${catalina.base}/myconfig.yml',\n        'file:${catalina.base}/myconfig.properties',\n]\n
\n

You may also include external configs using '-D' arguments which match the system properties\nthe application is seeking, preceded by an application prefix determined by info.app.name in your default application.yml, application.groovy or "app" if none exists. By default the following should work:

\n
-DappName.config="/path/to/config"\n-DappName.external.config="/path/to/config"\n-DappName.database.config="/path/to/config"\n-DappName.logging.config="/path/to/config"\n\n
\n

or using JNDI variables CONFIG, EXTERNAL_CONFIG, LOGGING_CONFIG, DATABASE_CONFIG in tomcat for example:

\n
<Context path="" docBase="/path/to/app.war"  reloadable="false">\n        <Environment name="APP_CONFIG"\n                value="file:/path/to/external_config.groovy"\n                type="java.lang.String"/>\n        <Environment name="DATABASE_CONFIG"\n                value="file:/path/to/external_config.database.groovy"\n                type="java.lang.String"/>\n</Context>\n
\n

While no-longer necessary as of version 1.1.0 of external-config, which this fork is based, for comparability you may edit your Grails projects Application.groovy and implement the trait com.neilab.plugins.config.ApplicationConfig (formally ExternalConfig):

\n
import com.neilab.plugins.config.ApplicationConfig\n\nclass Application extends GrailsAutoConfiguration implements ApplicationConfig {\n    static void main(String[] args) {\n        GrailsApp.run(Application, args)\n    }\n}\n
\n

This above is necessary only when ApplicationConfigRunListener is not executed, and personally have used it only when developing the plugin as an inline plugin where SpringApplicationRunListener was not loaded.

\n

Notes

\n

Notice, that ~/ references the users $HOME directory.\nNotice, that using a system property you should use single quotes because otherwise it's interpreted as a Gstring.

\n

The plugin will skip configuration files that are not found.

\n

For .groovy and .yml files the environments blocks in the config file are interpreted the same way, as in application.yml or application.groovy.

\n

Alternatively, you can make a gradle script to move the external configuration file to your classpath (e.g. /build/classes)

\n

Using IntelliJ or gradle to specify configurations via system properties

\n

When passing system properties via VM Options in IntelliJ or -D properties in gradle, it may be necessary to assign the parameters to the app via bootRun in your build.gradle configuration.

\n
//build.gradle\nbootRun {\n    systemProperties = System.properties\n}\n
\n

Scripts

\n

This plugin also includes two scripts, one for converting yml config, to groovy config,\nand one for converting groovy config to yml config. These scripts are not guaranteed to be\nperfect, but you should report any edge cases for the yml to groovy config here:\nhttps://github.com/virtualdogbert/GroovyConfigWriter/issues

\n

Sample usage:

\n
grails yml-to-groovy-config [ymlFile] [optional outputFile]\ngrails groovy-to-yml-config [ymlFile] [optional outputFile]\n
\n" }, { "deprecated": "This entry in the registry seems to be a duplicate of the entry named 'asset-pipeline-grails'. It should probably be removed from the registry to avoid confusion.", "bintrayPackage": { "name": "asset-pipeline", "repo": "plugins", "owner": "grails", "desc": "Grails asset-pipeline plugin", "labels": [ "asset-pipeline" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/bertramdev/asset-pipeline/issues", "latestVersion": "3.2.1", "updated": "2017-01-26T14:06:25.984Z", "systemIds": [ "org.grails.plugins:asset-pipeline" ], "vcsUrl": "https://github.com/bertramdev/asset-pipeline" }, "documentationUrl": "https://bertramdev.github.io/asset-pipeline/", "mavenMetadataUrl": null, "readme": null }, { "bintrayPackage": { "name": "asset-pipeline-grails", "repo": "asset-pipeline", "owner": "bertramlabs", "desc": "The Asset-Pipeline is a plugin used for managing and processing static assets in Grails applications. Asset-Pipeline functions include processing and minification of both CSS and JavaScript files. It is also capable of being extended to compile custom static assets, such as CoffeeScript.", "labels": [ "asset-pipeline" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/bertramdev/asset-pipeline/issues", "latestVersion": "5.0.1", "updated": "2024-09-13T18:26:28.000Z", "systemIds": [ "com.bertramlabs.plugins:asset-pipeline-grails" ], "vcsUrl": "https://github.com/bertramdev/asset-pipeline" }, "documentationUrl": "https://bertramdev.github.io/asset-pipeline/", "mavenMetadataUrl": "https://repo1.maven.org/maven2/com/bertramlabs/plugins/asset-pipeline-grails/maven-metadata.xml", "readme": null }, { "bintrayPackage": { "name": "asset-pipeline-handlebars-renderer", "repo": "plugins", "owner": "dpcasady", "desc": "Grails asset pipeline handlebars templates renderer plugin", "labels": [ "asset-pipeline", "handlebars" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/dpcasady/asset-pipeline-handlebars-renderer/issues", "latestVersion": "0.1", "updated": "2017-07-13T10:41:12.439Z", "systemIds": [ "org.grails.plugins:asset-pipeline-handlebars-renderer" ], "vcsUrl": "https://github.com/dpcasady/asset-pipeline-handlebars-renderer" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Asset Pipeline Handlebars Renderer Grails Plugin

\n

This plugin provides for server side execution of Handlebars.js templates. It is\nintended to compliment the handlebars-asset-pipeline plugin\nwhich compiles Handlebars templates into JavaScript for client side usage. The templates are compiled into Java\ncode using handlebars-java.

\n

Installation

\n

Add to build.gradle

\n
dependencies {\n     compile "org.grails.plugins:asset-pipeline-handlebars-renderer:0.1"\n}\n
\n

Configuration

\n

This plugin uses the same configuration as the handlebars-asset-pipeline plugin. Templates can be created in the standard assets/javascripts folder with an extension of .handlebars or .hbs. By default the templateRoot for your templates is specified as templates. This means that any handlebars file within assets/javascripts/templates/ will utilize its file name (without the extension) as its template name. So a template that lives at assets/javascripts/templates/my_template.hbs can be rendered as <handlebars:render template="my_template"/>.

\n

Usage

\n

A handlebars:render tag is provided to render handlebars templates similarly to how regular gsp templates are applied in views. Templates can be rendered inline:

\n
<handlebars:render model="[name: 'bob']">\n    <p>Hello {{name}}</p>\n</handlebars:render>\n
\n

Or they can be stored in a separate file and referenced by name:

\n
<handlebars:render template="home/hello" model="[name: 'bob']"/>\n
\n

For the above example, (assuming the default templateRoot) the template would be located at grails-app/assets/javascripts/templates/home/hello.hbs.

\n

If no model is supplied then the default page bindings (page scope variables) are used:

\n
<handlebars:render>\n    Hello {{name}} from the controller\n</handlebars:render>\n
\n

Behind the scenes, the taglib uses the handlebarsService to render templates. You can do the same if, for example, you want to render the template directly from a controller:

\n
def handlebarsService\n\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ndef list() {\n    render handlebarsService.apply("home/accounts", [accounts: Account.list()])\n}\n
\n" }, { "bintrayPackage": { "name": "async", "repo": "plugins", "owner": "grails", "desc": "Grails Async - Grails Async Libraries", "labels": [ "async" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails/grails-async/issues", "latestVersion": "5.0.2", "updated": "2024-01-09T11:43:22.000Z", "systemIds": [ "org.grails.plugins:async" ], "vcsUrl": "https://github.com/grails/grails-async" }, "documentationUrl": "https://async.grails.org/latest/guide/index.html", "mavenMetadataUrl": "https://repo1.maven.org/maven2/org/grails/plugins/async/maven-metadata.xml", "readme": "" }, { "bintrayPackage": { "name": "asynchronous-mail", "repo": "grails-asynchronous-mail", "owner": "gpc", "desc": "The plugin realises asynchronous mail sending. It stores messages in a DB and sends them asynchronously by a quartz job.", "labels": [ "async", "mail" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/gpc/grails-asynchronous-mail/issues", "latestVersion": "3.1.2", "updated": "2023-07-27T13:26:45.000Z", "systemIds": [ "io.github.gpc:asynchronous-mail" ], "vcsUrl": "https://github.com/gpc/grails-asynchronous-mail.git" }, "documentationUrl": "https://github.com/gpc/grails-asynchronous-mail", "mavenMetadataUrl": "https://repo1.maven.org/maven2/io/github/gpc/asynchronous-mail/maven-metadata.xml", "readme": "

See the README on GitHub

" }, { "comment": "This entry has had its owner changed from robertoschwald to symentis as that seems to be the maintained repo going forward. This comment can be removed if this is correct.", "bintrayPackage": { "name": "audit-logging", "repo": "plugins", "owner": "symentis", "desc": "Grails Audit-Logging Plugin.", "labels": [ "auditing" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/symentis/grails-audit-logging-plugin/issues", "latestVersion": "4.0.3", "updated": "2021-02-03T16:27:11.971Z", "systemIds": [ "org.grails.plugins:audit-logging" ], "vcsUrl": "https://github.com/symentis/grails-audit-logging-plugin" }, "documentationUrl": "https://symentis.github.io/grails-audit-logging-plugin", "mavenMetadataUrl": null, "readme": "

Grails Audit Logging Plugin

\n

Description

\n

The Audit Logging plugin for Grails adds generic event based Audit Logging to a Grails project.

\n

The master branch holds the codebase for plugin version 4.0.x (Grails 4.0.x).

\n

We currently work on a Grails 4.x branch using a new approach. See PR 212

\n

For older Grails versions, see "Supported Grails Versions" below.

\n

Documentation

\n\n

Supported Grails versions

\n\n

audit-quickstart

\n

You need to perform "grails audit-quickstart <package> <DomainClass>" after installing this plugin's 2.0.x version or later.

\n

With this, you get an auditlog domain class in your project which is fully under your control.\nThe domain name is registered in your application.groovy with key "grails.plugins.auditLog.auditDomainClassName".

\n

Example:

\n
grails audit-quickstart org.example.myproject MyAuditLogEvent\n
\n

Issue Management

\n

See GitHub Issues

\n

Pull Requests

\n

Pull requests are highly appreciated and welcome!

\n

Please add integration tests for new features to the audit-test application.

\n

Contributors

\n

Special thanks to all the contributors (in alphabetical order):

\n
Aaron Long\nAldrin\nAndrey Zhuchkov\nAnkur Tripathi\nBurt Beckwith\nbzamora33\nDanny Casady\nDennie de Lange\nDhiraj Mahapatro\nElmar Kretzer\nFelix Scheinost\nFernando Cambarieri\nGraeme Rocher\nJeff Palmer\nJorge Aguilera\nJuergen Baumann\nMadhava Jay\nMatt Long\nMatthew A Stewart\nPaul Taylor\nSami M\ufffd\ufffd\ufffd\ufffdkel\ufffd\ufffd\ufffd\ufffd\nSebastien Arbogast\nSemyon Atamas\nShawn Hartsock\nTom Crossland\n\nProject lead: Robert Oschwald\n
\n

Continuous Integration Server

\n

\"Build

\n

Bintray Repository

\n

\n

\"Download\"

\n
\n

\"YourKit

\n

YourKit is kindly supporting Grails open source projects with its full-featured Java Profiler.\nYourKit, LLC is the creator of innovative and intelligent tools for profiling\nJava and .NET applications. Take a look at YourKit's leading software products:\nYourKit Java Profiler and\nYourKit .NET Profiler.

\n" }, { "bintrayPackage": { "name": "audit-trail", "repo": "grails-plugins", "owner": "9ci", "desc": "Audit Trails Grails Plugin", "labels": [ "auditing" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/9ci/grails-audit-trail/issues", "latestVersion": "3.0.11", "updated": "2020-05-06T09:27:41.033Z", "systemIds": [ "org.grails.plugins:audit-trail" ], "vcsUrl": "https://github.com/9ci/grails-audit-trail" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

\"CircleCI\"\n\"9ci\"\n\n\"forthebadge\"\n\n\"forthebadge\"

\n

Install

\n
compile "org.grails.plugins:audit-trail:3.0.11"\n\n
\n

Overview

\n

This plugin lets you add an annotation to your domain classes so the necessary created/updated audit fields will get added. On save() the domain will get "stamped" after a new insert or update. This eliminates the need for setting up a base class.\nIt will automatically add fields based on your settings in Config.groovy.\nProvides an AST transformation annotation and hibernate events to take care of "stamping" for your gorm objects with the user who edited and/or created it as well as the edited and created dates.

\n

Goals

\n\n

Using the @gorm.AuditStamp annotation

\n

Add to your config.groovy each field you want added

\n

grails{\nplugin{\naudittrail{\t\ncreatedBy.field = "createdBy" //add whatever names you want used for the\neditedBy.field = "editedBy"\ncreatedDate.field = "createdDate"\neditedDate.field = "editedDate"\n}\n}\n}

\n

Add the annotation to your domain class

\n
@gorm.AuditStamp\nclass Note{\n\tString note\n}\n
\n

During compile time the AST transformation will add fields just as if you wrote your domain like so:

\n
class Note{\n\tString note\n\t\n\tLong createdBy \n\tLong editedBy \n\tDate editedDate\n\tDate createdDate \n\t\n\tstatic constaints = {\n\t\tcreatedBy   nullable:false,display:false,editable:false\n\t\teditedBy    nullable:false,display:false,editable:false\n\t\teditedDate  nullable:false,display:false,editable:false\n\t\tcreatedDate nullable:false,display:false,editable:false\n\t}\n\t\n\tdef beforeValidate() { //if this already existed then it just append the code\n\t\t//this sets the fields if this is a new (about to be inserted) instance \n\t\t...applicationContext.getBean('auditTrailHelper').initializeFields(this)\n\t}\n\t\n}\n
\n

No annotation

\n

The annotation is just an AST transformation as a convenience. You can add the fields manually to your domains that match whats you have configured in config.grooy and the events will fire on those fields. This includes other hibernate/java entities.\nIt uses the AuditTrailInterceptor to stamp the fields on the hibernate objects if they exists.

\n

Events and the interceptor

\n

As seen in the above example, this allows you to keep your fields set to "nullable:false" since this annotation will add/append code to the beforeValidate() to make sure the fields are initialized properly. It also setups

\n

Security

\n

The plugin defaults to using Spring Security but it is not dependent on it. If no currentUserClosure

\n

Configuration Options

\n

The following show the options and defaults. For a field to be added by the annotation at least on config setting needs to be present.\nNOTE: Remember to clean and re-compile after changing the config settings. All of the mods to the domain happen with and AST at compile time.

\n
grails{\n\tplugin{\n\t\taudittrail{\t\n\t\t\t// ** if field is not specified then it will default to 'createdBy'\n\t\t\tcreatedBy.field = "createdBy"  // createdBy is default\n\t\t\t// ** fully qualified class name for the type\t\n\t\t\tcreatedBy.type   = "java.lang.Long" //Long is the default\n\t\t\t// ** the constraints settings\n\t\t\tcreatedBy.constraints = "nullable:false,display:false,editable:false,bindable:false" \n\t\t\t// ** the mapping you want setup\n\t\t\tcreatedBy.mapping = "column: 'inserted_by'" //<-example as there are NO defaults for mapping\n\t\t\t\n\t\t\tcreatedDate.field = "createdDate"\n\t\t\tcreatedDate.type  = "java.util.DateTime" \n\t\t\tcreatedDate.constraints = "nullable:false,display:false,editable:false,bindable:false" \n\t\t\tcreatedDate.mapping = "column: 'date_created'" //<-NOTE: example as there are NO defaults for mapping\n\t\t\t\n\t\t\tetc.....\n\t\t\t\n\t\t\t//custom closure to return the current user who is logged in\n\t\t\tcurrentUserClosure = {ctx->\n\t\t\t\t//ctx is the applicationContext\n\t\t\t\t//default is basically\n\t\t\t\treturn springSecurityService.principal?.id\n\t\t\t}\n\t\t\t//there are NO defaults for companyId.\n\t\t\tcompanyId.field   = "companyId" //used for multi-tenant apps and is just the name of the field to use\n\t\t}\n
\n

Joda Time Example

\n

this also shows how you can set your own currentUserClosure for stamping the user fields

\n
grails{\n\tplugin{\n\t\taudittrail{\t\t\t\n\t\t\tcreatedBy.type   = "java.lang.String" \n\t\t\n\t\t\teditedBy.type   = "java.lang.String" \n\t\t\n\t\t\tcreatedDate.type  = "org.joda.time.DateTime" \n\t\t\tcreatedDate.mapping = "type: org.jadira.usertype.dateandtime.joda.PersistentDateTime"\n\t\t\n\t\t\teditedDate.type  = "org.joda.time.DateTime" \n\t\t\teditedDate.mapping = "type: org.jadira.usertype.dateandtime.joda.PersistentDateTime"\n\t\t\n\t\t\tcurrentUserClosure = {ctx->\n\t\t\t\treturn ctx.mySecurityService.currentUserLogin()\n\t\t\t}\n\t\t}\n\t}\n}\n
\n

Unit Testing

\n

In Grails 2 the config is available in your unit tests so it makes setting things up a bit easier now.\ngrails.plugin.audittrail.AuditTrailHelper has a mockForUnitTest(config,userVal=1) to make unit testing easier.\npass userVal in as something else if you want some other default or some other type for your createdBy and editedBy.\nTake a look at the source if you want to see what its doing.

\n
void testSave() {\n\tdef d = new TestDomain()\n\td.name = "test"\n\t//the AST from @gorm.AuditStamp adds a property "auditTrailHelper" to your domains\n\t//at run time it gets injected with the auditTrailHelper bean from the applicationContext\n\td.auditTrailHelper = AuditTrailHelper.mockForUnitTest(config)\n\td.save(failOnError:true)\n\tassert d.createdBy == 1 \n}\n
\n

changes from 1.2 -> 2.0 (many are breaking)

\n\n

changes in 2.0.4

\n\n

changes in 2.1

\n\n

Using AuditTrail in gradle multimodule projects

\n

AuditTrail AST Transoformation reads audit trail related settings from application.groovy.\nAs long as the project with AuditStamp annotation is root gradle project, it works just fine.\nHowever when the project is a module of a multimodule gradle project, A system property needs to be set to aid AST tranformation class find the correct application.groovy from module directory.

\n

This can be achieved by setting the module.path in build.gradle of submodule as shown below.

\n
compileGroovy {\n    groovyOptions.fork = true\n    String path = projectDir.absolutePath\n    groovyOptions.forkOptions.jvmArgs = ['-Dmodule.path=' + path]\n}\n
\n" }, { "comment": "This entry in the registry is for the umbrella project for all the AWS plugins from agorapulse. Perhaps this entry is not necessary as each separate plugin also has its own entry?", "bintrayPackage": { "name": "aws-sdk", "repo": "plugins", "owner": "agorapulse", "desc": "Grails AWS SDK plugin", "labels": [ "amazon", "aws", "cognito", "dynamodb", "kineses", "s3", "ses", "sns", "sqs", "sts" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/agorapulse/grails-aws-sdk/issues", "latestVersion": "2.4.15", "updated": "2022-07-20T06:42:00.000Z", "systemIds": [ ], "vcsUrl": "https://github.com/agorapulse/grails-aws-sdk" }, "documentationUrl": "https://agorapulse.github.io/grails-aws-sdk/", "mavenMetadataUrl": null, "readme": "

AWS SDK Grails Plugin

\n

\"Build \"Download\"

\n

Introduction

\n

The AWS SDK Plugins for Grails3 are a suite of plugins that adds support for the Amazon Web Services infrastructure services.

\n

The aim is to to get you started quickly by providing friendly lightweight utility Grails service wrappers, around the official AWS SDK for Java (which is great but very \ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdjava-esque\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd).\nSee this article for more info.

\n

The following services are currently supported:

\n\n

Please check each README for usage info.

\n

Testing

\n

How to Unit Test AWS Services with LocalStack and Testcontainers

\n

Bugs

\n

To report any bug, please use the project Issues section on GitHub.

\n

Compatibilty

\n

NOTE: For Grails 4 you should consider migrating to Micronaut AWS SDK as Miconaut is now the first class citizen in Grails. Use -micronaut-1.2 releases for Grails 4.0.x.

\n

| Grails | Plugin |\n| ------------- |---------------|\n| 3.3.x, 4.x | 2.2.x |\n| 3.2.x | 2.1.x |\n| 2.x | 1.x |

\n" }, { "bintrayPackage": { "name": "aws-sdk-cognito", "repo": "plugins", "owner": "agorapulse", "desc": "Grails AWS SDK Cognito plugin. Uses 'jitpack.io' maven repository.", "labels": [ "aws", "cognito" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/agorapulse/grails-aws-sdk/issues", "latestVersion": "2.4.15", "updated": "2022-07-20T06:42:00.000Z", "systemIds": [ "com.github.agorapulse.grails-aws-sdk:aws-sdk-cognito" ], "vcsUrl": "https://github.com/agorapulse/grails-aws-sdk" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Grails AWS SDK Cognito Plugin

\n

This repo has been migrated to the main AWS SDK Grails Plugin repo.

\n

Here his the latest version of it

\n" }, { "bintrayPackage": { "name": "aws-sdk-dynamodb", "repo": "plugins", "owner": "agorapulse", "desc": "Grails AWS SDK DynamoDB plugin. Uses 'jitpack.io' maven repository.", "labels": [ "aws", "dynamodb" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/agorapulse/grails-aws-sdk/issues", "latestVersion": "2.4.15", "updated": "2022-07-20T06:42:00.000Z", "systemIds": [ "com.github.agorapulse.grails-aws-sdk:aws-sdk-dynamodb" ], "vcsUrl": "https://github.com/agorapulse/grails-aws-sdk" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Grails AWS SDK DynamoDB Plugin

\n

This repo has been migrated to the main AWS SDK Grails Plugin repo.

\n

Here his the latest version of it

\n" }, { "bintrayPackage": { "name": "aws-sdk-kinesis", "repo": "plugins", "owner": "agorapulse", "desc": "Grails AWS SDK Kinesis plugin. Uses 'jitpack.io' maven repository.", "labels": [ "aws", "kinesis" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/agorapulse/grails-aws-sdk/issues", "latestVersion": "2.4.15", "updated": "2022-07-20T06:42:00.000Z", "systemIds": [ "com.github.agorapulse.grails-aws-sdk:aws-sdk-kinesis" ], "vcsUrl": "https://github.com/agorapulse/grails-aws-sdk" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Grails AWS SDK Kinesis Plugin

\n

This repo has been migrated to the main AWS SDK Grails Plugin repo.

\n

Here his the latest version of it

\n" }, { "bintrayPackage": { "name": "aws-sdk-s3", "repo": "plugins", "owner": "agorapulse", "desc": "Grails AWS SDK S3 plugin. Uses 'jitpack.io' maven repository.", "labels": [ "aws", "s3" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/agorapulse/grails-aws-sdk/issues", "latestVersion": "2.4.15", "updated": "2022-07-20T06:42:00.000Z", "systemIds": [ "com.github.agorapulse.grails-aws-sdk:aws-sdk-s3" ], "vcsUrl": "https://github.com/agorapulse/grails-aws-sdk" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Grails AWS SDK S3 Plugin

\n

This repo has been migrated to the main AWS SDK Grails Plugin repo.

\n

Here his the latest version of it

\n" }, { "bintrayPackage": { "name": "aws-sdk-ses", "repo": "plugins", "owner": "agorapulse", "desc": "Grails AWS SDK SES plugin", "labels": [ "aws", "ses" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/agorapulse/grails-aws-sdk/issues", "latestVersion": "2.4.15", "updated": "2022-07-20T06:42:00.000Z", "systemIds": [ "com.github.agorapulse.grails-aws-sdk:aws-sdk-ses" ], "vcsUrl": "https://github.com/agorapulse/grails-aws-sdk" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Grails AWS SDK SES Plugin

\n

This repo has been migrated to the main AWS SDK Grails Plugin repo.

\n

Here his the latest version of it

\n" }, { "bintrayPackage": { "name": "aws-sdk-sns", "repo": "plugins", "owner": "agorapulse", "desc": "Grails AWS SDK SNS plugin", "labels": [ "aws", "sns" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/agorapulse/grails-aws-sdk/issues", "latestVersion": "2.4.15", "updated": "2022-07-20T06:42:00.000Z", "systemIds": [ "com.github.agorapulse.grails-aws-sdk:aws-sdk-sns" ], "vcsUrl": "https://github.com/agorapulse/grails-aws-sdk" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Grails AWS SDK SNS Plugin

\n

This repo has been migrated to the main AWS SDK Grails Plugin repo.

\n

Here his the latest version of it

\n" }, { "bintrayPackage": { "name": "aws-sdk-sqs", "repo": "plugins", "owner": "agorapulse", "desc": "Grails AWS SDK SQS plugin", "labels": [ "aws", "sqs" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/agorapulse/grails-aws-sdk/issues", "latestVersion": "2.4.15", "updated": "2022-07-20T06:42:00.000Z", "systemIds": [ "com.github.agorapulse.grails-aws-sdk:aws-sdk-sqs" ], "vcsUrl": "https://github.com/agorapulse/grails-aws-sdk" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Grails AWS SDK SQS Plugin

\n

This repo has been migrated to the main AWS SDK Grails Plugin repo.

\n

Here his the latest version of it

\n" }, { "bintrayPackage": { "name": "aws-sdk-sts", "repo": "plugins", "owner": "agorapulse", "desc": "Grails AWS SDK STS plugin", "labels": [ "aws", "sts" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/agorapulse/grails-aws-sdk/issues", "latestVersion": "2.4.15", "updated": "2022-07-20T06:42:00.000Z", "systemIds": [ "com.github.agorapulse.grails-aws-sdk:aws-sdk-sts" ], "vcsUrl": "https://github.com/agorapulse/grails-aws-sdk" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Grails AWS SDK STS Plugin

\n

This repo has been migrated to the main AWS SDK Grails Plugin repo.

\n

Here his the latest version of it

\n" }, { "bintrayPackage": { "name": "babel-asset-pipeline", "repo": "plugins", "owner": "errbuddy", "desc": "Babel.js transformation for Asset-pipeline", "labels": [ "asset-pipeline", "babel" ], "licenses": [ "BSD 2-Clause" ], "issueTrackerUrl": "https://github.com/errbuddy/babel-asset-pipeline/issues", "latestVersion": "2.1.1", "updated": "2017-08-08T12:32:15.738Z", "systemIds": [ "net.errbuddy.plugins:babel-asset-pipeline", "net.errbuddy.plugins:add", "net.errbuddy.plugins:react-asset-pipeline" ], "vcsUrl": "https://github.com/errbuddy/babel-asset-pipeline" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

\"Build

\n

babel-asset-pipeline

\n

babel.js transformation for asset-pipeline

\n

usage

\n

simply add

\n
compile 'net.errbuddy.plugins:babel-asset-pipeline:2.0.6'\n
\n

to dependencies

\n

and

\n

The plugin will *ONLY process *.es6 and *.jsx files if not configured to also process *.js files .

\n

Configuration

\n

All configuration has to be done under grails.assets.babel. if you experience issues (e.g. configuration options not being picked up when building war files) you should add the configration to build.gradle too.

\n
grails:\n    assets:\n        babel:\n            enabled: true,\n            processor: 'direct'\n            processJsFiles: false\n            options: {blacklist: ['useStrict'], loose: 'all'}\n
\n

Options

\n
grails.assets.babel.enabled = true // boolean\n
\n

default to true. enables the plugin

\n
grails.assets.babel.processJsFiles = false // boolean\n
\n

defaults to false. Whether to process JsAssetFiles (.js) too. By default to Processor only touches Es6AssetFiles (.es6)!

\n
grails.assets.babel.processor = 'direct'\n
\n

defaults to direct which uses the "old" rhino->babel v5 Processor. see Processors section for other options

\n
grails.assets.babel.options = [blacklist: ['useStrict'], loose: 'all'] // babel transfom options. see https://babeljs.io/docs/usage/options/ for more information\n
\n

defaults to null. A Map of options passed to babels transform method. see https://babeljs.io/docs/usage/options/ for possible values. only used for "direct" processor, otherwise ignored

\n

Modules

\n
grails.assets.babel.options = [modules: 'amd', moduleIds: true]\n
\n

When the moduleIds option is set the plugin provides Babel with a moduleId for each file. The ID is the relative path of the file inside grails-app/assets/javascripts with the file extension removed.

\n
e.g.\n# File Path:\ngrails-app/assets/javascripts/foo/bar.js\n# Generated moduleId:\nfoo/bar\n
\n

Note: Explicit module IDs are not available when generating CommonJS modules.

\n

Processors

\n

since version 2.0 babel-asset-pipeline comes with a new Processor which uses webpack to transpile es6 code. There is some really important things to keep in mind when switching this on:

\n\n

Webpack

\n

Setup

\n

To use webpack you will need some prerequesites. Firstly you need to have node installed.\nIf you do not want to install it manually or you don't want to manage node yourself gradle-node-plugin should exactly be what you are looking for.\nThe only thing you will have to manually do in this case is configure the node executable (see config section below).

\n

Secondly you have to install gradle-babel-asset-pipeline-helper with npm. this can be done by running npm install --save gradle-babel-asset-pipeline-helper (you may need to npm init first). If you are using gradle-node-plugin you could copy https://github.com/peh/babel-test-app/blob/master/package.json to your project root and simply run gradle npmInstall\ngradle-babel-asset-pipeline-helper depends on everything that you will need to use webpack in your grails app and also comes with two default webpack configurations and run scripts that are being executed by the webpack processors.

\n

Lastly you should use <babel:webpack src="file.js" /> to reference your js files. This will come in handy if you are using the webpack dev server (otherwise it is not needed!)

\n

Restarting the WebpackDevserver

\n

In some cases it is needed to restart the devserver. Simply append ?restartWebpack=true to the url you are requesting. The Taglib will take care of killing and restarting the webpack devserver.

\n

Configuration

\n

There are a few additional configuration options you might need to touch

\n
grails.assets.babel.processor = "webpack" // or "webpack-dev-server"\n
\n

If you want to use Hot Module Reloading you can use webpack-dev-server. You should only do that in development environments for production you should always use webpack!

\n
grails.assets.babel.nodeExec = "/usr/local/bin/node"\n
\n

The node exectuable default to "/usr/local/bin/node". If you are on Windows or you are using gradle-node-plugin ( ornvm) you will have to change this to point to your local node exectuable

\n

For gradle-node-plugin users, node is installed in your projects local .gradle directory.

\n
grails.assets.babel.externalWebpackConfig = null\n
\n

This one is for advanced users only! By defining a different webpack config location you are overwriting the default configuration taken from gradle-babel-asset-pipeline-helper.\nThe default config is build using the buildConfig function.\nIf you want to use a custom one you can define a file here which is required by the package script.\nYour configuration should either be a webpack config object (see webpack documenation) or a function (which is recommended) which is then called with the same parameters the default build function is called with.\nThe default function should give you a fair idea on what the parameters are and how to use it properly.\nThis is usable for webpack-dev-server to but here it is important to stick closely to the default buildConfig() as HMR is breaking pretty easy when something is not configured right.

\n

Plugin Development

\n

If you want to help extending this plugin you can get setup in minutes by:

\n
git clone https://github.com/errbuddy/babel-asset-pipeline.git\ncd babel-asset-pipeline\n./gradlew npmInstall\n
\n

Now your local environment has the required nodeJs version installed and you can start hacking. Feel free to create a PR for your changes

\n" }, { "bintrayPackage": { "name": "bootstrap-framework", "repo": "gradle-plugins", "owner": "kensiprell", "desc": "Gradle plugin for integrating the Bootstrap Framework", "labels": [ "bootstrap", "fontawesome" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/kensiprell/bootstrap-framework/issues", "latestVersion": "1.0.3", "updated": "2017-11-07T07:26:49.452Z", "systemIds": [ "com.siprell.plugins:bootstrap-framework" ], "vcsUrl": "https://github.com/kensiprell/bootstrap-framework" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

This plugin is no longer maintained.

\n

Gradle plugin for integrating the Bootstrap Framework and Font Awesome

\n

\"Download\"

\n

Bootstrap bills itself as "the most popular HTML, CSS, and JS framework for developing responsive, mobile first projects on the web."

\n

Font Awesome is the "iconic font and CSS toolkit."

\n

If you have a question, suggestion, or want to report a bug, please submit an issue. I will reply as soon as I can.

\n

Highlights

\n\n

Sample Application

\n

This Grails sample application demonstrates how to use the plugin.

\n

Installation

\n

Add the following lines to your application's build.gradle file. The commented-out lines show the plugin default values, and if you are using Grails, they are not required for the plugin to work. See the Configuration Options section for the details.

\n
buildscript {\n    ext {\n         //bootstrapFramework = [\n         //    version             : "3.3.5",\n         //    cssPath             : "grails-app/assets/stylesheets",\n         //    jsPath              : "grails-app/assets/javascripts",\n         //    useIndividualJs     : false,\n         //    useLess             : false,\n         //    invalidVersionFails : false,\n         //    fontAwesome : [\n         //       install             : false\n         //       version             : "4.3.0",\n         //       useLess             : false\n         //       invalidVersionFails : false\n         //    ]\n         //]\n    }\n    repositories {\n        jcenter()\n    }\n    dependencies {\n        classpath "com.siprell.plugins:bootstrap-framework:1.0.3"\n    }\n}\n\napply plugin: "com.siprell.plugins.bootstrap-framework"\n
\n

Configuration Options

\n

The following options can be configured in the bootstrapFramework Map.

\n

bootstrapFramework.version

\n

Use the property below to change the Bootstrap Framework version used by your application.

\n
version : "3.3.1"\n
\n

bootstrapFramework.cssPath

\n

Use the property below to define the location where the Bootstrap CSS, fonts, and LESS files are copied.

\n
cssPath : "src/main/web-app/resources/css"\n
\n

bootstrapFramework.jsPath

\n

Use the property below to define the location where the Bootstrap JavaScript files are copied.

\n
jsPath : "src/main/web-app/resources/js"\n
\n

bootstrapFramework.useIndividualJs

\n

If the property below is set to true, the plugin will copy all individual JavaScript files to "${bootstrapFramework.jsPath}/bootstrap". Otherwise, it will only copy the bootstrap.js file to the directory.

\n
useIndividualJs : true\n
\n

bootstrapFramework.useLess

\n

If the property below is set to true, the plugin will copy all Bootstrap Framework LESS and mixin files to "${bootstrapFramework.cssPath}/bootstrap/less".

\n
useLess : true\n
\n

invalidVersionFails

\n

The invalidVersionFails property can be configured individually for bootstrapFramework and bootstrapFramework.fontAwesome. When the property is at its default of false and you have entered an invalid version number, the plugin will search the build/tmp directory for other versions of the appropriate zip file and use the one with the highest version number. It will also display a warning message in the console.

\n

You can disable this behavior by setting this property to true. If the plugin cannot download the version you specified, it will throw an org.gradle.api.InvalidUserDataException.

\n
bootstrapFramework = [\n    invalidVersionFails : true\n    fontAwesome : [\n        install : true,\n        invalidVersionFails : true\n    ]\n]\n
\n

bootstrapFramework.fontAwesome.install

\n

If bootstrapFramework.fontAwesome.install is set to true, the plugin will install the Font Awesome fonts using the default plugin version without LESS support.

\n
bootstrapFramework = [\n    fontAwesome : [\n        install : true\n    ]\n]\n
\n

bootstrapFramework.fontAwesome.version

\n

You can change the Font Awesome version by setting the bootstrapFramework.fontAwesome.version property.

\n
bootstrapFramework = [\n    fontAwesome : [\n        install : true\n        version : "4.2.0"\n    ]  \n]\n
\n

bootstrapFramework.fontAwesome.useLess

\n

You can add LESS support for Font Awesome by setting the bootstrapFramework.fontAwesome.useLess property.

\n
bootstrapFramework = [\n    fontAwesome : [\n        install : true\n        useLess : true\n    ]  \n]\n
\n

How the Plugin Works

\n

The plugin downloads the appropriate Bootstrap or Font Awesome zip file and copies it to your application's build/tmp directory. The plugin will extract the necessary files and copy them to the directories defined by the bootstrapFramework.cssPath and bootstrapFramework.jsPath properties.

\n

The files are copied into the directory trees shown below. It is important that you do not put any files in the two bootstrap directories ("${bootstrapFramework.cssPath}/bootstrap" and "${bootstrapFramework.jsPath}/bootstrap") or the font-awesome directory ("${bootstrapFramework.cssPath}/font-awesome") because they will be overwritten.

\n

The bootstrap-all.js, bootstrap-all.css, bootstrap-less.less, font-awesome-all.css, and font-awesome-less.less files are generated for the asset-pipeline plugin if you are using Grails or the word "assets" is contained in the bootstrapFramework.jsPath property.

\n

Directory bootstrapFramework.jsPath:

\n
|    bootstrap-all.js\n|----bootstrap/\n|    |    affix.js\n|    |    alert.js\n|    |    bootstrap.js\n|    |    etc.\n
\n

Directory bootstrapFramework.cssPath:

\n
|    bootstrap-all.css\n|    bootstrap-less.less\n|----bootstrap/\n|    |----css/\n|    |    |    bootstrap-theme.css\n|    |    |    bootstrap.css\n|    |----fonts/\n|    |    |    glyphicons-halflings-regular.eot\n|    |    |    etc.\n|    |----less/\n|    |    |    alerts.less\n|    |    |    badges.less\n|    |    |    etc.\n|    |    |----mixins/\n|    |    |    |    alerts.less\n|    |    |    |    background-variant.less\n|    |    |    |    etc.\n|    font-awesome-all.css\n|    font-awesome-less.less\n|----font-awesome/\n|    |----css/\n|    |    |    font-awesome.css\n|    |----fonts/\n|    |    |    FontAwesome.otf\n|    |    |    etc.\n|    |----less/\n|    |    |    animated.less\n|    |    |    etc.\n
\n

User Task

\n

You can use the task shown below to display the default Bootstrap Framework and Font Awesome versions used by the plugin.

\n
./gradlew bootstrapFrameworkVersions\n
\n

or

\n
./gradlew bFV\n
\n

The output will be similar to:

\n
3.3.5 is the default Bootstrap Framework version.\n4.3.0 is the default Font Awesome version.\n
\n

Glyphicons

\n

The Glyphicons icons are available as described in the Bootstrap Components section of the Bootstrap Framework documentation.

\n

Asset Pipeline Usage

\n

The remaining sections outline how to include Bootstrap Framework and Font Awesome in your application using the asset-pipeline-core plugin and its less-asset-pipeline module.

\n

JavaScript

\n

The instructions below assume the manifest file is in the grails-app/assets/javascripts directory.

\n
Add all Bootstrap JavaScript Files
\n

Add the line below to a manifest:

\n
//= require bootstrap-all\n
\n

Or add the line below to a GSP:

\n
<asset:javascript src="bootstrap-all.js"/>\n
\n
Add individual Bootstrap JavaScript files
\n

Ensure you set the parameter below to true as described above:

\n
bootstrapFrameworkUseIndividualJs = true\n
\n

Add a line similar to the one below to a manifest:

\n
//= require bootstrap/bootstrap-affix\n
\n

Or add the line below to a GSP:

\n
<asset:javascript src="bootstrap/bootstrap-affix.js"/>\n
\n

Stylesheets

\n

The instructions below assume the manifest file is in the grails-app/assets/stylesheets directory.

\n
Add all Bootstrap and Font Awesome CSS Files
\n

Add the lines below to a manifest:

\n
*= require bootstrap-all\n*= require font-awesome-all\n
\n

Or add the lines below to a GSP:

\n
<asset:stylesheet src="bootstrap-all.css"/>\n<asset:stylesheet src="font-awesome-all.css"/>\n
\n
Add individual Bootstrap CSS Files
\n

Add the line below to a manifest:

\n
*= require bootstrap/css/bootstrap-theme\n
\n

Or add the line below to a GSP:

\n
<asset:stylesheet src="bootstrap/css/bootstrap-theme.css"/>\n
\n

LESS

\n

Add LESS Files

\n

Add the lines below to a manifest:

\n
*= require bootstrap-less\n*= require font-awesome-less\n
\n

Or add the line below to a GSP:

\n
<asset:stylesheet src="bootstrap-less.css"/>\n<asset:stylesheet src="font-awesome-less.css"/>\n
\n

LESS Customizations

\n

If LESS support is configured for either Bootstrap Framework or Font Awesome, the plugin will create the appropriate LESS file in your application's bootstrapFramework.cssPath directory. If you later decide not to use LESS, the plugin will delete the LESS and mixin files, but it will not delete the bootstrap-less.less or the font-awesome-less.less file. Should you decide to turn LESS support back on, your customized LESS files will still be available.

\n

Use bootstrap-less.less for customizing the Bootstrap Framework:

\n
/*\n* This file is for your Bootstrap Framework less and mixin customizations.\n* It was created by the bootstrap-framework plugin.\n* It will not be overwritten.\n*\n* You can import all less and mixin files as shown below,\n* or you can import them individually.\n* See https://github.com/kensiprell/bootstrap-framework/blob/master/README.md#less\n*/\n\n@import "bootstrap/less/bootstrap.less";\n\n/*\n* Your customizations go below this section.\n*/\n
\n

Use font-awesome-less.less for customizing Font Awesome:

\n
* Font Awesome by Dave Gandy - http://fontawesome.io\n*\n* This file is for your Font Awesome less and mixin customizations.\n* It was created by the bootstrap-framework plugin.\n* It will not be overwritten.\n*\n* You can import all less and mixin files as shown below,\n* or you can import them individually.\n* See https://github.com/kensiprell/bootstrap-framework/blob/master/README.md#font-awesome-less\n*/\n\n@import "font-awesome/less/font-awesome.less";\n\n@fa-font-path: "/assets/font-awesome/fonts";\n\n/*\n* Your customizations go below this section.\n*/\n
\n" }, { "bintrayPackage": { "name": "boselecta", "repo": "maven", "owner": "vahid", "desc": "Websocket autocomplete/ multi dependency selection plugin for grails 3", "labels": [ "autocomplete" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/vahidhedayati/grails-boselecta-plugin/issues", "latestVersion": "3.0.4", "updated": "2016-04-13T21:40:52.542Z", "systemIds": [ "org.grails.plugins:boselecta" ], "vcsUrl": "https://github.com/vahidhedayati/grails-boselecta-plugin" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Boselecta plugin

\n

Side note - similar / related projects

\n\n

Grails plugin that uses default WebSocket technology to interact with your domainClasses and produce dependent form / options that depend on one another. The format to define select functionality / auto complete are identical. Auto complete requires additional boolean values to be passed to make it auto complete.

\n
Select box dependencies data comes from WebSocket Client running within your application (as part of the plugin)
\n
AutoComplete input areas use HTML5 dataList, data for dataList provided by backend WebSocket Connection.
\n

Walkthrough Video - youtube, Everything you need to know about boselecta

\n

\"diagram\"

\n

More information to help with diagram

\n

BoSelecta can be incorporated to an existing grails app running ver 2>+. Supports both resource (pre 2.4) /assets (2.4+) based grails sites.

\n
Plugin will work with tomcat 7.0.54 + (inc. 8) running java 1.7+
\n
Dependency
\n

Dependency Grails 3:

\n
    compile "org.grails.plugins:boselecta:3.0.4"\n
\n

codebase for grails 3.X

\n

Dependency Grails 2:

\n
\tcompile ":boselecta:0.2" \n
\n

codebase for grails 2.X

\n

######test site for grails 2

\n

######test site for grails 3

\n

###Latest updates (after video published):\nA further lock down has been introduced, with the assumption that most people will be looking up domain objects with single dependencies.\nThis means, typically I expect an end user to map from continent to country to city and so on. So its one to one relationship between each object. For this reason the default call now only supports one relation, so:

\n
<bo:selecta\n...  \ndomain="package.domainClass1"\n..\ndomain2="package.domainClass2"\n..\n/>\n
\n

domain will be the primary object itself (so a listing of that object, domain2 is the entity that it has that relationship with.

\n

If you attempt to exceed and use domain3 and on. The plugin will not work. You can from now use selecta2 for those relations with depth

\n
<bo:selecta2\ndomainDepth="4"\n...  \ndomain="package.domainClass1"\n..\ndomain2="package.domainClass2"\n..\ndomain3="package.domainClass3"\n..\ndomain4="package.domainClass4"\n..\n/>\n
\n

Testing plugin

\n

Config.groovy overrides

\n

[domainDepth explained] (https://github.com/vahidhedayati/grails-boselecta-plugin/wiki/domainDepth-explained)

\n
grails BoSelecta Plugin usage
\n

JSON Formatting.

\n
What is front-end / back-end WebSocket connections ?
\n

##Examples:

\n
Basic example:
\n

Example 1: Connector / selectPrimary into default g:select box. (found in above testbo project)

\n
    \n
  1. Initiate a master socket connection, <bo:connect handles all the information flowing back from backend websocket. So this is your main and only connection required on any given page. Take a note of the user and job names, they must match all the calls on this page.
  2. \n
\n

Both the two code blocks below in one gsp:

\n
<bo:connect user="myuser" job="job1" />\n
\n

Now that we have configured our master listener, lets configure one connection with a relation that is returned to a normal blank select box

\n
<form  action="example5">\n\n<bo:selecta \nid="MyCountry1" name="MyCountry1" job= "job1" user="myuser" domainDepth="0" formatting="JSON"\ndomain='ajaxdependancyselectexample.MyCountry' searchField='countryName' collectField='id'\ndomain2='ajaxdependancyselectexample.MyCity' bindid="mycountry.id" searchField2='cityName' collectField2='id'\nappendValue='' appendName='Updated' noSelection="['': 'Please choose Continent']" setId="MyCity1" />\n\n<g:select name="MyCity1" id="MyCity1" optionKey="id" optionValue="cityName" from="[]" required="required" noSelection="['': 'Please choose Country']" />\n<input type=submit value=go> \n</form>\n
\n

If you have used ajaxdependancy selection, a lot of the above input will look familiar.\nYou are now giving the backend the ID of your primary selection MyCountry1, you are telling it what domain is which makes this a primary call and then returns MyCountry.countryName and MyCountry.id to the primary box, you are then setting the setId as MyCity1 and saying domain2 is MyCity and to search/collect cityName/id.

\n

Example 2: Connector / primary / into Secondary into g:select: (found in above testbo project)

\n

Identical to above, but in this example we iterate over the relations using <bo:select passing domain2 object which be the next object so on the secondary objects there is no domain= value defined.

\n
<bo:connect user="randomUser2" job="job2" />\n\n<g:form name="myForm" action="example5">    \n<bo:selecta \n  id="MyContinent2" name="MyContinent2" setId="MyCountry11"\n  job= "job2" user="randomUser2" domainDepth="0"    \n  domain='ajaxdependancyselectexample.MyContinent' searchField='continentName' collectField='id'\n  domain2='ajaxdependancyselectexample.MyCountry' bindid="mycontinent.id" searchField2='countryName'\n  appendValue='' appendName='Updated' collectField2='id' noSelection="['': 'Please choose Continent']" />\n\n <bo:selecta id="MyCountry11" name="MyCountry11"\n job= "job2" user="randomUser2" domainDepth="0" setId="MyCity11"\n domain2='ajaxdependancyselectexample.MyCity' bindid="mycountry.id" searchField2='cityName' collectField2='id'\n formatting="JSON" appendValue=''  appendName='Updated' noSelection="['': 'Please choose Continent']" />\n\n <bo:selecta \n name="MyCity11" id="MyCity11" job= "job2" user="randomUser2" domainDepth="0" setId="MyShop12" \n domain2='ajaxdependancyselectexample.MyShops' bindid="mycity.id" searchField2='shopName' collectField2='id'\n appendValue='' appendName='Updated' formatting="JSON" noSelection="['': 'Please choose Country 1111']"/>\n\n <g:select \n name="MyShop12" id="MyShop12" optionKey="id" optionValue="shopName" \n from="[]" required="required" noSelection="['': 'Please choose City']" \n />\n <g:submitButton name="submit"/>  \n </g:form>\n
\n

Example 3: Defined pre selected values across multiple objects + randomized user within gsp

\n

Example 4: Defined pre selected values across less multiple objects + randomized user within controller

\n

Example 5: Defined pre selected values same as example3 but with JSON return object

\n

Example 6: Multiple relationship per domainClass example i.e. object1 has many up to Xth relations with object2 3 4..XXX

\n

Example 7: applicable to all methods - reuse of the taglib multiple times on the same page

\n

Example 8: No reference or loose dependency relation between a secondary called object and the next domainClass

\n

Example 9: No reference relationship with secondary object that then returns back into a normal relationship object

\n

Example 10: Primary object with a No reference relationship

\n

Example 11: Auto complete a few hasMany to a noref relation\nUsing the same Tag to acheive autoComplete\nIn this example (not on actual link, the user is being defined as a variable and reused - this now makes it a dynamic user but same on that one page.

\n

The difference with this call and select is that as you can see on the first example it has autoComplete="true" and if this is the primary object then also autoCompletePrimary="true", if second object it just needs the first tag. Follow example below.. There are two additional fields hiddenField and jsonField. In autoComplete, the results are returned from html5 dataList. I have added data-value and parse that into the hidden field for jsonField and hiddenField gets set to the or collectField of the value selected. The rest is like above.

\n
<% def myuser = bo.randomizeUser('user': 'random1') %>\n\n<bo:connect user="${myuser}" job="job3"/>\n\n<form action="example5">\n\n<bo:selecta \n    autoComplete="true" autoCompletePrimary="true" \n    job="job3" user="${myuser}" id="MyContinent2" name="MyContinent2" setId="MyCountry11" \n    hiddenField="VahidHidden_" jsonField="VahidJSON_" formatting="JSON"\n    domain='ajaxdependancyselectexample.MyContinent' searchField='continentName' collectField='id'\n    domain2='ajaxdependancyselectexample.MyCountry' bindid="mycontinent.id" \n    searchField2='countryName' collectField2='id' />\n\t\n    <bo:selecta \n\tautoComplete="true" \n\tjob="job3" user="${myuser}" id="MyCountry11" name="MyCountry11" \n\thiddenField="NextHidden_" jsonField="NextJSON_" formatting="JSON"\n\tdomain2='ajaxdependancyselectexample.MyCity' bindid="mycountry.id"\n\tsearchField2='cityName' collectField2='id' setId="MyCity11" />\n\t\n    <bo:selecta\n    \tautoComplete="true"\n\tjob="job3" user="${myuser}" formatting="JSON"\n\tname="MyCity11" id="MyCity11" \n\thiddenField="myHidden_" jsonField="myJSON_"\n\tdomain2='ajaxdependancyselectexample.MyShops' searchField2='shopName' collectField2='id' \n\tbindid="mycity.id"  setId="secondarySearch4" \n\t/>\n\t\n    <bo:selecta \n    \tautoComplete="true"\n    \tjob= "job121" user="${myuser }"\tformatting="JSON" id="secondarySearch4" name="NAMEOFBorough"  \n\thiddenField="myHidden_" jsonField="myJSON_"\n\tdomain2='ajaxdependancyselectexample.MyBorough' searchField='actualName' collectField='id' \n\tbindid='myborough' value=''\n    />\n    <input type=submit value=go>\n</form>\n
\n

Example 12: Select To AutoComplete

\n

Example 13:AutoComplete To Select

\n

Example 14: AutoComplete To Select from select to another select

\n" }, { "bintrayPackage": { "name": "browser-detection", "repo": "grails-plugins", "owner": "mathifonseca", "desc": "Grails Browser Detection Plugin", "labels": [ ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/mathifonseca/grails-browser-detection/issues", "latestVersion": "3.4.0", "updated": "2018-03-14T19:17:36.286Z", "systemIds": [ "org.grails.plugins:browser-detection" ], "vcsUrl": "https://github.com/mathifonseca/grails-browser-detection" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

grails-browser-detection

\n

\"Build

\n

This plugin provides a service and tag library for browser detection. It parses User-Agent in order to identify client's browser, operating system, etc. It depends on user-agent-utils library from HaraldWalker.\nIf you want to contribute, report issues or just check the code. You can find it at GitHub.

\n

Here are some of the things that you can currently do with this plugin. All this operations can be used from GSPs or you can use the UserAgentIdentService anywhere in your code.

\n

Using UserAgentIdentService:

\n
class TestController {\n\n    def userAgentIdentService\n  \n    def index() {\n        if (userAgentIdentService.isMobile()) {\n            println 'Hello mobile device!'\n            if (userAgentIdentService.isWindowsPhone()) {\n                println 'Wow! Does this still exist?'\n            }\n        } else {\n            println 'Hello desktop browser!'\n            if (userAgentIdentService.isInternetExplorer()) {\n                println 'Redirecting to Chrome download page...'\n            }\n        }\n    }\n\n}\n
\n

Detecting Browsers

\n
<browser:isMsie> This is Internet Explorer </browser:isMsie>\n<browser:isSafari> This is Safari </browser:isSafari>\n<browser:isChrome> This is Chrome </browser:isChrome>\n<browser:isFirefox> This is Firefox </browser:isFirefox>\n<browser:isOpera> This is Opera </browser:isOpera>\n
\n

Detecting Devices

\n
<browser:isiPhone> This is iPhone </browser:isiPhone>\n<browser:isiPad> This is iPad </browser:isiPad>\n<browser:isMobile> Mobile phones or Android, iPhone, iPad, iPod, Blackberry, etc. </browser:isMobile>\n
\n

Detecting Operative Systems

\n
<browser:isWindows> This is Windows </browser:isWindows>\n
\n

Other operations

\n

You can use the following structure that emulates switch behavior:

\n
<browser:choice>\n\t<browser:isChrome></browser:isChrome>\n\t<browser:isIE6></browser:isIE6>\n\t<browser:isIE7></browser:isIE7>\n\t<browser:otherwise></browser:otherwise>\n</browser:choice>\n
\n

Or the one below:

\n
<browser:isSafari versionGreater="5">\n\tThis text is rendered if Safari version is greater than 5.\n\tFor example, 5.0.1, 5.1\n</browser:isSafari>\n<browser:isFirefox version="3.*">\n\tIt works for all Firefox versions like 3.1, 3.6 and so on\n</browser:isFirefox>\n<browser:isMsie versionLower="7">\n\tInternet Explorer 5.0, Internet Explorer 6.0\n</browser:isMsie>\n
\n

At the moment, wildcards are allowed only for version attribute. Be aware that 5.1 is greater than 5 and 5.0 equals to 5.

\n

All of these taglibs have their negative assert by starting with isNot. For example:

\n
<browser:isNotSafari>\n\tThis text is rendered if the browser IS NOT Safari.\n</browser:isNotSafari>\n<browser:isNotFirefox>\n\tThis text is rendered if the browser IS NOT Firefox.\n</browser:isNotFirefox>\n<browser:isNotMsie>\n\tThis text is rendered if the browser IS NOT Internet Explorer.\n</browser:isNotMsie>\n<browser:isNotChrome>\n\tThis text is rendered if the browser IS NOT Chrome.\n</browser:isNotChrome>\n
\n" }, { "bintrayPackage": { "name": "build-test-data", "repo": "plugins", "owner": "longwa", "desc": "Grails build-test-data plugin", "labels": [ "testing" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/longwa/build-test-data/issues", "latestVersion": "4.0.0", "updated": "2019-12-20T01:02:42.869Z", "systemIds": [ "io.github.longwa:build-test-data", "org.grails.plugins:build-test-data" ], "vcsUrl": "https://github.com/longwa/build-test-data" }, "documentationUrl": "https://longwa.github.io/build-test-data/", "mavenMetadataUrl": null, "readme": "

\"Build

\n

Build Test Data Grails Plugin

\n

Grails 3.3 and 4.0

\n

http://longwa.github.io/build-test-data/index

\n

Grails 2.4 - 3.2

\n

https://github.com/longwa/build-test-data/wiki

\n" }, { "bintrayPackage": { "name": "cache", "repo": "plugins", "owner": "grails", "desc": "Grails Cache Plugin", "labels": [ "cache" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails/grails-cache/issues", "latestVersion": "7.0.0", "updated": "2024-03-21T08:40:30.000Z", "systemIds": [ "org.grails.plugins:cache" ], "vcsUrl": "https://github.com/grails/grails-cache" }, "documentationUrl": "https://grails.github.io/grails-cache/", "mavenMetadataUrl": "https://repo1.maven.org/maven2/org/grails/plugins/cache/maven-metadata.xml", "readme": null }, { "bintrayPackage": { "name": "cache-ehcache", "repo": "plugins", "owner": "grails", "desc": "Provides an ehcache implementation of the cache plugin", "labels": [ "cache", "ehcache" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails-plugins/grails-cache-ehcache/issues", "latestVersion": "3.0.0", "updated": "2020-07-01T19:32:27.992Z", "systemIds": [ "org.grails.plugins:cache-ehcache" ], "vcsUrl": "https://github.com/grails-plugins/grails-cache-ehcache" }, "documentationUrl": "https://grails-plugins.github.io/grails-cache-ehcache/latest/", "mavenMetadataUrl": null, "readme": "

\"Build

\n

Grails Cache Ehcache Plugin

\n

Makes Ehcache the cache implementation for the Grails Cache Plugin

\n

Grails 3

\n

See https://plugins.grails.org/plugin/grails/cache-ehcache and Documentation

\n

Grails 2

\n

See https://grails.org/plugin/cache-ehcache and Documentation

\n

Branches

\n

The current master branch is for 3.x versions of the plugin compatible with Grails 3. There is a 1.x branch for on-going maintenance of 1.x versions of the plugin compatible with Grails 2. Please submit any pull requests to the appropriate branch. Changes to the 1.x branch will be merged into the master branch if appropriate.

\n" }, { "bintrayPackage": { "name": "cache-guava", "repo": "plugins", "owner": "mkobel", "desc": "The guava cache provides a simple in memory cache with maximal capacity and TTL.", "labels": [ "cache" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/itds-ch/grails-cache-guava/issues", "latestVersion": "1.0.0", "updated": "2020-07-03T07:46:52.226Z", "systemIds": [ "org.grails.plugins:cache-guava" ], "vcsUrl": "https://github.com/itds-ch/grails-cache-guava" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

grails-cache-guava

\n

This Grails plugin extends the grails-cache plugin.

\n

The guava cache provides a simple in memory cache with maximal capacity and TTL.

\n

Usage

\n

Dependency

\n
dependencies {\n    compile 'org.grails.plugins:cache:4.0.0'\n    compile 'org.grails.plugins:cache-guava:1.0.0'\n}\n
\n

Configuration

\n
grails:\n  cache:\n    guava:            \n      defaultTtl: 3600\n      caches:\n        message:\n          maxCapacity: 5000\n          ttl: 60\n        maps:\n          maxCapacity: 6000\n          ttl: 30\n        countries:\n          maxCapacity: 1000\n
\n

The GrailsGuavaCacheManager is automatically configured by the plugin.

\n

Annoations and Services

\n

Just use grails-cache's annotations and services as described in\nits documentation

\n" }, { "bintrayPackage": { "name": "cache-headers", "repo": "plugins", "owner": "grails", "desc": "Improve your application performance with browser caching, with easy ways to set caching headers\nin controller responses", "labels": [ "cache" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails-plugins/cache-headers/issues", "latestVersion": "2.0.2", "updated": "2017-07-13T17:33:18.181Z", "systemIds": [ "org.grails.plugins:cache-headers" ], "vcsUrl": "https://github.com/grails-plugins/cache-headers" }, "documentationUrl": "https://grails-plugins.github.io/cache-headers/", "mavenMetadataUrl": null, "readme": "

\"Build

\n

Grails Cache Headers Plugin

\n

his plugin helps you Improve your application performance with browser caching, with easy ways to set caching headers in controller responses, and elegant ways to deal with ETag and Last-Modified generation and checking.\nYou can use this plugin to prevent caching of pages (eg forms), specify long term caching on infrequently changing content, and pass information to caching servers between the client and your app, and also to avoid regeneration of content if it has not changed since the client last downloaded it (even though the client may have an indication it has expired).

\n

See the documentation for more information

\n

Distribution

\n

Software is distributed in Bintray

\n" }, { "bintrayPackage": { "name": "cascade-validation", "repo": "grails-plugins", "owner": "ctoestreich", "desc": "Grails Cascade Validation Plugin", "labels": [ "validation" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/Grails-Plugin-Consortium/grails-cascade-validation/issues", "latestVersion": "2.0.2", "updated": "2016-03-31T13:31:54.830Z", "systemIds": [ "org.grails.plugins:cascade-validation", "org.grails.plugins:grails-cascade-validation" ], "vcsUrl": "https://github.com/Grails-Plugin-Consortium/grails-cascade-validation" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

grails-cascade-validation

\n

See: [https://github.com/rmorrise/grails-cascade-validation/wiki/How-to-use-cascade-validation].

\n

This plugin establishes a 'cascade' constraint property for validateable objects. If "cascade:true" is set on a nested object, the nested object's validate() method will be invoked and the results will be reported as part of the parent object's validation.

\n

To use this plugin, add the plugin to BuildConfig.groovy:

\n
     plugins {\n         //CSC custom plugin for 'cascade' constraint\n         compile ":cascade-validation:0.1.4"\n     }\n
\n

Here is an example of a command object that uses the plugin:

\n
 @Validateable\n class PhoneNumber {\n     long id\n     String countryCode\n     String areaCode\n     String number\n     String extension\n     TelephoneType telephoneType\n     boolean isPrimary\n\n     static constraints = {\n         areaCode(blank: false)\n         number(blank: false)\n         telephoneType(cascade: true)\n     }\n\n     @Validateable\n     static class TelephoneType {\n         String id\n         boolean countryCodeRecommended\n\n         static constraints = {\n             id(blank: false)\n             countryCodeRecommended(nullable: false)\n         }\n     }\n }\n
\n

When the cascade: constraint is added on the telephoneType property, this enables nested validation. When the phoneNumber.validate() method is called, the telephoneType.validate() method will also be invoked. Field errors that are added to the telephoneType will also be added to the parent phoneNumber object.

\n

This plugin was originally based on a blog post by Eric Kelm and is used here with Eric's permission.

\n" }, { "bintrayPackage": { "name": "cassandra", "repo": "plugins", "owner": "grails", "desc": "GORM - Grails Data Access Framework", "labels": [ "cassandra", "gorm" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails/gorm-cassandra/issues", "latestVersion": "6.1.0", "updated": "2017-03-27T13:56:24.682Z", "systemIds": [ "org.grails.plugins:cassandra" ], "vcsUrl": "https://github.com/grails/gorm-cassandra" }, "documentationUrl": "https://gorm.grails.org/latest/cassandra/manual/", "mavenMetadataUrl": null, "readme": "

GORM for Cassandra

\n

This project implements GORM for the Cassandra Column Database.

\n

For more information see the following links:

\n\n

For the current development version see the following links:

\n\n" }, { "bintrayPackage": { "name": "ckeditor", "repo": "plugins", "owner": "stefanogualdi", "desc": "CKeditor web WYSIWYG editor integration plugin.", "labels": [ "ckeditor" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/stefanogualdi/grails-ckeditor/issues", "latestVersion": "4.5.9.0", "updated": "2016-08-27T09:08:35.970Z", "systemIds": [ "org.grails.plugins:ckeditor" ], "vcsUrl": "https://github.com/stefanogualdi/grails-ckeditor" }, "documentationUrl": "https://stefanogualdi.github.io/grails-ckeditor/", "mavenMetadataUrl": null, "readme": "

CKeditor plugin for Grails

\n

The user guide can be found here: Documentation

\n" }, { "bintrayPackage": { "name": "phone-number-constraint", "repo": "grails-plugins", "owner": "sbglasius", "desc": "Grails Phone Number Constraint Plugin", "labels": [ "validation" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/gpc/grails-phone-number-constraint/issues", "latestVersion": "1.0.0", "updated": "2024-02-06T11:35:24.000Z", "systemIds": [ "io.github.gpc:phone-number-constraint" ], "vcsUrl": "https://github.com/gpc/grails-phone-number-constraint" }, "documentationUrl": null, "mavenMetadataUrl": "https://repo.maven.apache.org/maven2/io/github/gpc/phone-number-constraint/maven-metadata.xml", "readme": "This plugin establishes a `phoneNumber` constraint property for validateable objects, that being domain objects, and objects implementing `grails.validation.Validateable`. It relies on Google's [libphonenumber](https://github.com/google/libphonenumber) Java implementation" }, { "bintrayPackage": { "name": "cmeditor", "repo": "maven", "owner": "frnktrgr", "desc": "CMEditor is a simple way to use the popular CodeMirror web editor in grails applications.", "labels": [ "cmeditor", "codemirror" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/RRZE-PP/grails-cmeditor/issues", "latestVersion": "2.7.8", "updated": "2019-05-13T09:05:24.098Z", "systemIds": [ "org.grails.plugins:cmeditor" ], "vcsUrl": "https://github.com/RRZE-PP/grails-cmeditor" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

CMEditor

\n

CMEditor is a simple way to use the popular CodeMirror web editor in grails applications. You can use it to edit pretty much anything that can be mapped to a file-like object. I.e. something with a filename and text-content. If your model requires additional fields this is supported, too.

\n

For example managing your library could be done by mapping filename to "$author - $title". The tabbed editor then could manage everything: Author, title, publication year and - of course - the books content in a nice-to-use CodeMirror editor. You could even edit multiple books simultaneously.

\n

Check out our demo grails project.

\n

Usage

\n

You currently have the Grails 3 branch checked out. If you wish to use the plugin with Grails 2, checkout the branch 'grails-2.x' and follow the instruction in its README.md.

\n

Add cmeditor as a plugin to your grails project's build.gradle

\n
    plugins {\n        compile 'de.rrze:cmeditor:+'\n    }\n
\n

The plugin depends on jQuery, but does not require it via the assets plugin, because this might overwrite jQuery instances (and registered in jQuery plugins) from other grails plugins. Please ensure that jQuery is loaded before the CMEditor's assets. And that no other jQuery instance is loaded thereafter (e.g. by your layout).

\n
  <asset:javascript src="path/to/your/jQuery.js"/>\n  <asset:javascript src="cmeditor.js"/>\n  <asset:stylesheet href="cmeditor.css"/>\n\n
\n

When adding a textarea or tabbed editor you have to supply a name-attribute. After document initialization you can access the corresponding javascript CMEditor-object by calling CMEditor.getInstance("<nameAttributeValue>)". For an API of the class see the CMEditor.js file in grails-app/js/web-app/js/.

\n

Tabbed Editor

\n

The tabbed editor is useful to edit more than one file at once. They are loaded and stored seamlessly using ajax to a controller of your choice.

\n

For further documentation please visit our project wiki for information on the API.

\n

If you need additional input fields, you can provide them in the body of the tag. All elements with the class cmeditor-field there will be serialized using their name as key and sent along with the document's content.

\n

A simple example would look like this:

\n
    <cmeditor:tabs name="book" options="[defaultContent:'Lorem ipsum sit dolor']" ajax="[getURL:createLink(action: 'ajaxGet')+'?name=']">\n      <label for="author"> <g:message code="myLibrary.author.label" default="Author" /></label>\n      <g:textField name="author" class="cmeditor-field" /> <br />\n\n      <label for="title"><g:message code="myLibrary.title.label" default="Title" /></label>\n      <g:textField name="title" class="cmeditor-field" />\n    </cmeditor:tabs>\n
\n

The resulting CMEditor would be similar to this:\n\"Recorded

\n

Textareas

\n

You can substitute a <g:textArea name=""/> with <cmeditor:textArea name=""/>.

\n

For further documentation please visit our project wiki for information on the API.

\n

So for example use: <g:textArea name="foobar" binding="vim" options="[readOnly: true"] />

\n" }, { "bintrayPackage": { "name": "coffee-asset-pipeline", "repo": "asset-pipeline", "owner": "bertramlabs", "desc": "Easily process CoffeeScript files with the asset-pipeline plugin. Package includes both jvm coffee runtime as well as the ability to use the coffeescript npm module if detected.", "labels": [ "asset-pipeline", "coffeescript" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/bertramdev/asset-pipeline/issues", "latestVersion": "5.0.1", "updated": "2024-09-13T18:26:36.000Z", "systemIds": [ "com.bertramlabs.plugins:coffee-asset-pipeline" ], "vcsUrl": "https://github.com/bertramdev/asset-pipeline" }, "documentationUrl": "https://bertramdev.github.io/asset-pipeline/", "mavenMetadataUrl": "https://repo1.maven.org/maven2/com/bertramlabs/plugins/coffee-asset-pipeline/maven-metadata.xml", "readme": null }, { "bintrayPackage": { "name": "command", "repo": "plugins", "owner": "virtualdogbert", "desc": "Grails command plugin", "labels": [ "command-objects", "validation" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/virtualdogbert/command/issues", "latestVersion": "4.0.0", "updated": "2018-06-26T23:35:43.271Z", "systemIds": [ "org.grails.plugins:command" ], "vcsUrl": "https://github.com/virtualdogbert/command" }, "documentationUrl": "https://virtualdogbert.github.io/command/", "mavenMetadataUrl": null, "readme": "

The command Plugin, give Grails a convention for command objects, and adds an ErrorsHandler AST to reduce error handling boilerplate.

\n

For documentation see the github page:\ndocumentation

\n" }, { "bintrayPackage": { "name": "compass-asset-pipeline", "repo": "asset-pipeline", "owner": "bertramlabs", "desc": "Provides Compass/SCSS Build support using the jruby runtime. Any compass project can be adjusted to be built by the asset-pipeline and used in applications.", "labels": [ "asset-pipeline", "compass", "scss", "css" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/bertramdev/asset-pipeline/issues", "latestVersion": "4.3.0", "updated": "2023-05-01T16:24:04.000Z", "systemIds": [ "com.bertramlabs.plugins:compass-asset-pipeline" ], "vcsUrl": "https://github.com/bertramdev/asset-pipeline.git" }, "documentationUrl": "https://bertramdev.github.io/asset-pipeline/", "mavenMetadataUrl": "https://repo1.maven.org/maven2/com/bertramlabs/plugins/compass-asset-pipeline/maven-metadata.xml", "readme": null }, { "bintrayPackage": { "name": "console", "repo": "grails-plugins", "owner": "sheehan", "desc": "A web-based Groovy console for interactive runtime application management and debugging.", "labels": [ "console", "management", "debugging" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/sheehan/grails-console/issues", "latestVersion": "2.1.1", "updated": "2018-01-23T03:19:17.309Z", "systemIds": [ "org.grails.plugins:grails-console" ], "vcsUrl": "https://github.com/sheehan/grails-console" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Summary

\n

A web-based Groovy console for interactive runtime application management and debugging

\n

\"Screenshot\"

\n

Installation

\n

The 1.X version is for Grails 2.

\n

The 2.0.X version is for Grails 3.0 - 3.2.

\n

The 2.1.X version is for Grails 3.3+.

\n

Grails 2

\n

Add a dependency in BuildConfig.groovy:

\n
grails.project.dependency.resolution = {\n  // ...\n  plugins {\n    runtime ':console:1.5.12'\n    // ...\n  }\n}\n
\n

Grails 3+

\n

Note: If using Grails 3.0.4, you need to update the asset-pipeline dependency in build.gradle to 3.0.6 or greater. 3.0.5 is used by default and has a bug that prevents the console page from rendering.

\n

Note: If using Grails 3.0.12, you will need to add this to your configuration: grails.resources.pattern = '/**'. There is a bug related to resource paths.

\n

Add a dependency in build.gradle

\n
runtime 'org.grails.plugins:grails-console:2.1.1'\n
\n

Usage

\n

Use a browser to navigate to the /console page of your running app, e.g. http://localhost:8080/{app-name}/console

\n

Type any Groovy commands in the console text area, then click on the execute button. The console plugin relies on Groovy Shell. Lookup Groovy Shell documentation for more information.\nThe Groovy Shell uses the Grails classloader, so you can access any class or artifact (e.g. domain classes, services, etc.) just like in your application code.

\n

Saving/loading scripts

\n

Click on the Save button to save the current script.

\n

Use the Storage pane to navigate existing files. Click on a file to load it into the editor.

\n

There are currently two storage options available:

\n

Local Storage

\n

Local Storage uses HTML5 Web Storage. The files are serialized and stored in the browser as a map under the key gconsole.files.

\n

Remote Storage

\n

Remote Storage uses the filesystem of the server on which the application is running.

\n

Writing to the browser console

\n

Calls made to the implicit console variable will be executed on the browser's console.\nThe arguments are serialized as JSON and the calls are queued to run after the script completes.

\n

Example:\n\"Screenshot\"

\n

Implicit variables

\n

The following implicit variables are available:

\n\n

See Script Examples for example usage.

\n

Keyboard Shortcuts

\n

| Key | Command |\n|---|---|\n| Ctrl-Enter / \ufffd\ufffd\ufffd\ufffd\ufffd\ufffd-Enter | Execute |\n| Ctrl-S / \ufffd\ufffd\ufffd\ufffd\ufffd\ufffd-S | Save |\n| Esc | Clear output |

\n

Configuration

\n

The following configuration options are available:

\n

| Property | Description |\n|---|---|\n| grails.plugin.console.enabled | Whether to enable the plugin. Default is true for the development environment, false otherwise. |\n| grails.plugin.console.baseUrl | Base URL for the console controller. Can be a String or a List of Strings if having multiple URLs is desired. Default uses createLink(). |\n| grails.plugin.console.fileStore.remote.enabled | Whether to include the remote file store functionality. Default is true. |\n| grails.plugin.console.fileStore.remote.defaultPath | Default path when browsing remote files. Default is /. |\n| grails.plugin.console.layout | Used to override the plugin's GSP layout. |\n| grails.plugin.console.newFileText | Text to display as a template for new files. Can be used to add frequently used imports, environment specific warnings, etc... Defaults to empty. |\n| grails.plugin.console.tabSize | The width of a tab character. Defaults to 4. |\n| grails.plugin.console.indentWithTabs | Whether indents should use tabs rather than spaces. Default is false. |\n| grails.plugin.console.indentUnit | How many spaces a block should be indented. Default is 4. |\n| grails.plugin.console.csrfProtection.enabled | Whether to enable CSRF protection. Default is true. |

\n

Security

\n

By default (as of v1.5.0) the console plugin is only enabled in the development environment. You can enable or disable it for any environment with\nthe grails.plugin.console.enabled config option in Config.groovy / application.groovy (Grails 3). If the plugin is enabled in non-development environments, be sure to guard access using a security plugin like Spring Security Core or Shiro. For Grails 2.x, the paths /console/** and /plugins/console*/** should be secured. For Grails 3.x, the paths /console/** and /static/console/** should be secured.

\n

Spring Security Core example:

\n
grails.plugin.springsecurity.controllerAnnotations.staticRules = [\n    [pattern:"/console/**",          access:['ROLE_ADMIN']],\n    [pattern:"/plugins/console*/**", access:['ROLE_ADMIN']],  // Grails 2.x\n    [pattern:"/static/console/**",   access:['ROLE_ADMIN']], // Grails 3.x\n]\n
\n

Another example restricting access to localhost IPs:

\n
grails.plugin.springsecurity.controllerAnnotations.staticRules = [\n    [pattern:"/console/**",          access:["hasRole('ROLE_ADMIN') && (hasIpAddress('127.0.0.1') || hasIpAddress('::1'))"]],\n    [pattern:"/plugins/console*/**", access:["hasRole('ROLE_ADMIN') && (hasIpAddress('127.0.0.1') || hasIpAddress('::1'))"]], // Grails 2.x\n    [pattern:"/static/console/**",   access:["hasRole('ROLE_ADMIN') && (hasIpAddress('127.0.0.1') || hasIpAddress('::1'))"]], // Grails 3.x\n]\n
\n

Authors

\n\n

Development

\n

Please see CONTRIBUTING.md

\n" }, { "bintrayPackage": { "name": "consulta-nif", "repo": "plugins", "owner": "puravida-software", "desc": "Consulta el nombre registrado en la AEAT para un NIF dado", "labels": [ ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://gitlab.com/puravida-software/consulta-nif/issues", "latestVersion": "0.1", "updated": "2018-01-10T09:34:46.818Z", "systemIds": [ "com.puravida:consulta-nif" ], "vcsUrl": "https://gitlab.com/puravida-software/consulta-nif/tree/master" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": null }, { "bintrayPackage": { "name": "converters", "repo": "plugins", "owner": "grails", "desc": "Provides JSON and XML converters", "labels": [ "json", "xml" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails/grails-plugin-converters/issues", "latestVersion": "5.0.0", "updated": "2024-02-26T10:59:18.000Z", "systemIds": [ "org.grails.plugins:converters" ], "vcsUrl": "https://github.com/grails-plugins/grails-plugin-converters" }, "documentationUrl": null, "mavenMetadataUrl": "https://repo1.maven.org/maven2/org/grails/plugins/converters/maven-metadata.xml", "readme": "

Grails Converters

\n

This is the Converters plugin that has been part of Grails core up until version 3.3 and now is a standalone plugin.

\n

Users of Grails 3.3.x and above should use this plugin.

\n

Installation

\n

Simply add the dependency to your build.gradle file:

\n
compile "org.grails.plugins:converters"\n
\n" }, { "bintrayPackage": { "name": "cookie", "repo": "grails-plugins", "owner": "ctoestreich", "desc": "Grails Cookie Plugin", "labels": [ "cookies" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/Grails-Plugin-Consortium/grails-cookie/issues", "latestVersion": "2.0.5", "updated": "2016-04-21T01:59:54.523Z", "systemIds": [ "org.grails.plugins:cookie", "org.grails.plugins:grails-cookie" ], "vcsUrl": "https://github.com/Grails-Plugin-Consortium/grails-cookie" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Grails Cookie Plugin

\n

\"Build

\n

This plugin makes dealing with cookies easy. Provides an injectable service and tag to easily get, set, and delete cookies with one line.

\n

It's RFC 6265 compliant.

\n

Installation

\n

To install the cookie plug-in just add to build.gradle:

\n
    \n    compile 'org.grails.plugins:grails-cookie:2.0.3'\n    \n
\n

Configuration

\n

You can configure in Config.groovy or application.yml how long the default cookie age will be (in seconds) when not explicitly supplied while setting a cookie.

\n
grails.plugins.cookie.cookieage.default = 86400 // if not specified default in code is 30 days\n
\n

Usage

\n

You have two ways to work with cookies:

\n\n

Example of setting a new cookie:

\n
// This sets a cookie with the name `username` to the value `cookieUser123` with a expiration set to a week, defined in seconds\nresponse.setCookie('username', 'cookieUser123', 604800)\n// will use default age from Config (or 30 days if not defined)\nresponse.setCookie('username', 'cookieUser123')\n\n// using service\ndef cookieService // define field for DI\n...\ncookieService.setCookie('username', 'cookieUser123', 604800)\n
\n

To get the cookie value:

\n
request.getCookie('username') // returns 'cookieUser123'\n\n// using service\ndef cookieService // define field for DI\n...\ncookieService.getCookie('username') // returns 'cookieUser123'\n
\n

To delete the cookie (actually it set new expired cookie with same name):

\n
response.deleteCookie('username') // deletes the 'username' cookie\n// using service\ndef cookieService // define field for DI\n...\ncookieService.deleteCookie('username')\n
\n

All this methods has other signatures and you can find all of them in CookieService JavaDoc's.

\n

You can check out Demo project and also you can find details of implementation in CookieRequestSpec and CookieResponseSpec.

\n

Configuration

\n

You can configure default values of attributes in Config.groovy.

\n

Default Max Age

\n

Default expiration age for cookie in seconds. Max-Age attribute, integer.

\n

If it has value -1 cookie will not stored and removed after browser close.

\n

If it has null value or unset, will be used 30 days, i.e. 2592000 seconds.

\n

Can't has value 0, because it means that cookie should be removed.

\n
grails.plugins.cookie.cookieage.default = 360 * 24 * 60 * 60\n
\n

Default Path

\n

Default path for cookie selection strategy, string.

\n\n

If default path is null or unset, it will be used 'context' strategy

\n
grails.plugins.cookie.path.defaultStrategy = 'context'\n
\n

Default Secure

\n

Default secure cookie param. Secure cookie available only for HTTPS connections. Secure attribute, boolean.\nIf default secure is null or unset, it will set all new cookies as secure if current connection is secure

\n
grails.plugins.cookie.secure.default = null\n
\n

Default HTTP Only

\n

Default HTTP Only param that denies accessing to JavaScript's document.cookie.

\n

If null or unset will be true

\n
grails.plugins.cookie.httpOnly.default = true\n
\n

You can find details of implementation in CookieServiceDefaultsSpec.

\n

External Config

\n

If you use property files to inject values to plugins at runtime. This is now supported as of version 1.0.2. This means that inside your external foo.properties file you can specify the following.

\n
grails.plugins.cookie.httpOnly.default=true\n
\n

The string value will correctly be treated as a boolean.

\n

Changelog

\n

All releases

\n

v2.0.5 For Grails 3.0

\n

Source

\n\n

v2.0.3 For Grails 3.0

\n

Source

\n\n

v2.0.2 For Grails 3.0

\n

Source

\n\n

v2.0.1 For Grails 3.0

\n

Source

\n\n

v2.0 For Grails 3.0

\n

Source

\n

v1.4 For Grails 2.4

\n

Source

\n\n

v1.2 Fixed bug with path.defaultStrategy option

\n

Source

\n\n

v1.1.0 Fixed bug with defaults not configured in Config

\n

Source

\n\n

v1.0.1 Fixed bug with defaults not configured in Config

\n

Source

\n\n

v1.0 Production ready version

\n

Source

\n\n

v0.60 Last release with deprecated taglib and methods in service

\n

Source

\n\n

v0.3

\n

Source

\n

In the v0.3 release a big issue was fixed that now sets the cookie's path to the root / context.\nOtherwise it was setting the path to the same as the controller/service that triggered it.\nMost users I believe will want this behavior. If setting the path is desired, that can be accommodated.\nPlease contact me or do a pull request if you'd like that.

\n" }, { "deprecated": "It seems that this project is continued in a fork by double16 and published at the same maven coordinates. This entry in the registry should probably be removed to avoid confusion.", "bintrayPackage": { "name": "cookie-session", "repo": "maven", "owner": "benlucchesi", "desc": "Grails cookiesession plugin", "labels": [ "cookies", "http-session" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/benlucchesi/grails-cookie-session", "latestVersion": "3.0.1", "updated": "2016-03-31T13:31:55.060Z", "systemIds": [ "org.grails.plugins:cookie-session" ], "vcsUrl": "https://github.com/benlucchesi/grails-cookie-session-v2.git" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Cookie Session Grails Plugin

\n

Current Version: 3.0.1

\n

The Cookie Session plugin enables grails applications to store session data in http cookies between requests instead of in memory on the server. Client sessions are transmitted from the browser to the application with each request and transmitted back with each response. This allows application deployments to be more stateless. Benefits of managing sessions this way include:

\n\n

Installation

\n

edit build.gradle add the following line under the plugins closure

\n

compile ":grails-cookie-session-v3:3.0"

\n

Configuration

\n

The following parameters are supported directly by the cookie-session-v3 plugin. Note, additional configuration is needed for large session support. See additional instructions below.

\n

Parameters

\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
<tr>\n  <td>grails.plugin.cookiesession.condenseexceptions</td>\n  <td>false</td>\n  <td>replaces instances of Exceptions objects in the session with the Exception.getMessage() in the session (see SessionPersistanceListener for further details)</td> \n</tr>\n\n<tr>\n  <td>grails.plugin.cookiesession.serializer</td>\n  <td>'java'</td>\n  <td>specify serializer used to serialize session objects. valid values are: 'java', 'kryo', or the name of a spring bean that implement SessionSerializer. See section on Serializers below.</td> \n</tr>\n\n<tr>\n  <td>grails.plugin.cookiesession.usesessioncookieconfig</td>\n  <td>false</td>\n  <td>version 2.0.12+ uses the ServletContext.SessionCookieConfig to configure cookies used to store the session. values from SessionCookieConfig override config parameters setsecure, sethttp, path, domain, comment, sessiontimeout, and cookiename. See notes below on use of this config option.</td> \n</tr>\n\n<tr>\n  <td>grails.plugin.cookiesession.springsecuritycompatibility</td>\n  <td>false</td>\n  <td>true to configure enhanced compatibility with spring security, false to disable.</td> \n</tr>\n\n<tr>\n  <td>grails.plugin.cookiesession.setsecure</td>\n  <td>false</td>\n  <td>calls Cookie.setSecure on cookie-session cookies. This flag indicates to browsers whether cookies should only be sent over secure connections.</td> \n</tr>\n\n<tr>\n  <td>grails.plugin.cookiesession.httponly</td>\n  <td>false</td>\n  <td>calls Cookie.setHttpOnly on cookie-session cookies. This flag indicates to browsers that the cookie should not be made available to scripts.</td>\n</tr>\n\n<tr>\n  <td>grails.plugin.cookiesession.path</td>\n  <td>/</td>\n  <td>calls Cookie.setPath on cookie-session cookies. This limits the paths for which the browser should send the cookie.</td>\n</tr>\n\n<tr>\n  <td>grails.plugin.cookiesession.domain</td>\n  <td>-unset-</td>\n  <td>calls Cookie.setDomain on cookie-session cookies if set. This tells the browsers which domains the cookie is valid for; if unset, then the cookie is valid for the current host only.</td>\n</tr>\n\n<tr>\n  <td>grails.plugin.cookiesession.comment</td>\n  <td>-unset-</td>\n  <td>calls Cookie.setComment on cookie-session cookies.</td>\n</tr>\n\n\n<tr>\n  <td>grails.plugin.cookiesession.id</td>\n  <td><b>deprecated</b></td>\n  <td>deprecated. use the 'grails.plugin.cookiesession.cookiename' setting.</td>\n</tr>\n\n<tr>\n  <td>grails.plugin.cookiesession.timeout</td>\n  <td><b>deprecated</b></td>\n  <td>deprecated. use the 'grails.plugin.cookiesession.sessiontimeout' setting.</td>\n</tr>\n\n<tr>\n  <td>grails.plugin.cookiesession.hmac.secret</td>\n  <td><b>deprecated</b></td>\n  <td>deprecated. use the 'grails.plugin.cookiesession.secret' setting.</td>\n</tr>\n\n<tr>\n  <td>grails.plugin.cookiesession.hmac.id</td>\n  <td><b>deprecated</b></td>\n  <td>deprecated. no equivelent setting is present in this version of the plugin.</td>\n</tr>\n\n<tr>\n  <td>grails.plugin.cookiesession.hmac.algorithm  </td>\n  <td><b>deprecated</b></td>\n  <td>deprecated. use the 'grails.plugin.cookiesession.cryptoalgorithm' settings.</td>\n</tr>\n
\n \n
namedefaultdescription
grails.plugin.cookiesession.enabledfalseenables or disables the cookie session.
grails.plugin.cookiesession.encryptcookietrueenable or disable encrypting session data stored in cookies.
grails.plugin.cookiesession.cryptoalgorithmBlowfishThe cryptographic algorithm used to encrypt session data (i.e. Blowfish, DES, DESEde, AES). NOTE: the secret must be compatible with the crypto algorithm. Version 2.0.12 supports non-ECB cipher modes, such as 'Blowfish/CBC/PKCS5Padding', that require an initialization vector
grails.plugin.cookiesession.secretgeneratedThe secret key used to encrypt session data. If not set, a random key will be created at runtime. Set this parameter if deploying multiple instances of the application or if sessions need to survive a server crash or restart. sessions to be recovered after a server crash or restart.
grails.plugin.cookiesession.cookiecount5The maximum number of cookies that are created to store the session in
grails.plugin.cookiesession.maxcookiesize2048The max size for each cookie expressed in bytes.
grails.plugin.cookiesession.sessiontimeout0The length of time a session can be inactive for expressed in seconds. -1 indicates that a session will be active for as long as the browser is open.
grails.plugin.cookiesession.cookienamegsession-XX number of cookies will be written per the cookiecount parameter. Each cookie is suffixed with the integer index of the cookie.
\n

Example

\n

application.yml

\n
    grails:\n      plugin:\n        cookiesession:\n          enabled: true\n          encryptcookie: true\n          cryptoalgorithm: "Blowfish"\n          secret: "This is my secret."\n          cookiecount: 10\n          maxcookiesize: 2048  // 2kb\n          sessiontimeout: 3600 // one hour\n          cookiename: 'gsession'\n          condenseexceptions: false\n          setsecure: true\n          sethttponly: false\n          path: '/'\n          comment: 'Acme Session Info'\n          serializer: 'kryo'\n          springsecuritycompatibility: true\n
\n

Understanding cookiecount and maxcookiesize

\n

The maximum session size stored by this plugin is calculated by (cookiecount * maxcookiesize). The reason for these two parameters is that through experimentation, some browsers didn't reliably set large cookies set before the subsequent request. To solve this issue, this plugin supports configuring the max size of each cookie stored and the number of cookies to span the session over. The default values are conservative. If sessions exceed the max session size as configured, first increase the cookiecount and then the maxcookiesize parameters.

\n

Enabling large session

\n

To enable large sessions, increase the max http header size for the servlet container you are using.

\n

Due to the potentially large amount of data that may be stored, consider setting it to something large, such as 262144 ( 256kb ).

\n

the following are for grails 2.x, needs to be updated for 3.x - investigating

\n

Tomcat

\n

Edit the server.xml and set the connector's maxHttpHeaderSize parameter.

\n

When developing in grails, configure the embedded tomcat server with the tomcat configuration event:

\n
    \n
  1. \n

    create the file scripts/_Events.groovy in your project directory

    \n
  2. \n
  3. \n

    add the following code:

    \n
    eventConfigureTomcat = {tomcat ->\n  tomcat.connector.setAttribute("maxHttpHeaderSize",262144)\n}\n
    \n
  4. \n
\n

Jetty (2.0.5+)

\n

Edit the jetty.xml or web.xml and set the connector's requestHeaderSize and responseHeaderSize parameters.

\n
    \n
  1. \n

    create the file scripts/_Events.groovy in your project directory

    \n
  2. \n
  3. \n

    add the following code:

    \n
    eventConfigureJetty = {jetty ->\n  jetty.connectors[0].requestHeaderSize = 262144\n  jetty.connectors[0].responseHeaderSize = 262144\n}\n
    \n
  4. \n
\n

SessionPersistenceListener

\n

SessionPersistenceListener is an interface used inspect the session just after its been deserialized from persistent storage and just before being serialized and persisted.

\n

SessionPersistenceListener defines the following methods:\nvoid afterSessionRestored( SerializableSession session )\nvoid beforeSessionSaved( SerializableSession session )

\n

To use, write a class that implements this interface and define the object in the application's spring application context (grails-app/conf/spring/resources.groovy). The CookieSession plugin will scan the application context and retrieve references to all classes that implement SessionPersistenceListener. The order that the SessionPersistenceListeners are called is unspecified. For an example of how to implement a SessionPersistenceListener, see the ExceptionCondenser class which is part of the cookie-session plugin.

\n

The ExceptionCondenser uses beforeSessionSaved() to replace instances of Exceptions the exception's message. This is useful because some libraries, notably the spring-security, store exceptions in the session, which can cause the cookie-session storage to overflow. The ExceptionCondenser can be installed by either adding it in the application context or by enabling it with the convenience settings grails.plugin.cookiesession.condenseexceptions = true.

\n

Configuring Serialization

\n

The grails.plugin.cookiesession.serializer config setting is used to pick which serializer the cookie-session plugin will use to serialize sessions. Currently, only two options are supported: 'java' and 'kryo'. 'java' is used to pick the java.io API serializer. This serializer has proven to be reliable and works 'out of the box'. 'kryo' is used to pick the Kryo serializer (http://code.google.com/p/kryo/). The Kryo serializer has many benifits over the Java serializer, primarily serialized results are significantly smaller which reduces the size of the session cookies. However, the Kryo serializer requires configuration to work correctly with some grails and spring objects. By default the kryo serializer is configured to serialize GrailsFlashScope and other basic grails objects. If the application uses spring-security, you must enabled springsecuritycompatibility for the cookie-session plugin. Additionally you should verify that the serializer is successfully serializing all objects that will be stored in the session. Configure info level logging for 'com.granicus.grails.plugins.cookiesession.CookieSessionRepository' for test and development environments to monitor the serialization and deserialization process. If objects fail to serialize, please report an issue to this github project; a best effort will be made to make the kryo serializer as compatible as possible. If the kryo serializer doesn't work for your application, consider falling back to the java serializer or implementing your own SessionSerializer as described below.

\n

Spring Security Compatibility

\n

Spring Security Compatibility, configured with the springsecuritycompatibility setting, directs the cookie-session plugin to adjust its behavior to be more compatible with the spring-security-core plugin.

\n

The primary issue addressed in this mode relates to when the spring-security core's SecurityContextPersistenceFilter writes the current security context to the SecurityContextRepository. In most cases, the SecurityContextPersistenceFilter stores the current security context after the current web response has been written. This is a problem for the cookie-session plugin because the session is stored in cookies in the web response. As a result, the current security context is never saved in the session, in effect losing the security context after each request. To work around this issue, spring security compatibility mode causes the cookie-session plugin to write the current security context to the session just before the session is serialized and saved in cookies. The security context is stored under the key that the SecurityContextRepository expects to find the security context.

\n

The next issue that Spring Security Compatibility addresses involves cookies saved in the DefaultSavedRequest. DefaultSavedRequest is created by spring security core and stored in the session during redirects, such as after authentication. Spring Security Compatibility causes the cookie-session plugin to detect the presense of a DefaultSavedRequest in the session and remove any cookie-session cookies it may be storing. This ensures that old session information doesn't replace more current session information when following a redirects. This also reduces the size of the the serialized session because the DefaultSavedRequest is storing an old copy of a session in the current session. Finally, Spring Security Compatibility adds custom kryo serializers (when kryo serialization is enabled) to successfully serialize objects that kryo isn't capable of serializing by default.

\n

When compatibility with Spring Security is enabled the plugin may enforce new session creation if none exists yet. The reason is that without a session present the Security Context would not be persisted and propagaded between requests. This would manifest as an intermittent issue depending whether or not the application uses session for some other purpose or not (e.g. flash scope).

\n

use of SessionCookieConfig

\n

SessionCookieConfig is a interface introduced in Servlet 3.0 and is used to specify configuration parameters of session cookies. If you enable the grails.plugin.cookiesession.usesessioncookieconfig parameter, then this interface is used to configure the cookie session cookies. In order for this option to work, the servlet context must be servlet context version 3.0 or great.

\n

The following is an example of how to use the SessionCookieConfig to configure cookies in the init closure in BootStrap.groovy.

\n
    if( servletContext.majorVersion >= 3 ){\n      servletContext.sessionCookieConfig.name = 'sugar2'\n      servletContext.sessionCookieConfig.secure = false\n      servletContext.sessionCookieConfig.maxAge = 3600\n    }\n
\n

WARNING on updating cookie specifications and general recomendations

\n

Be warned, updating the cookie specification can cause unexpected results and cause your application to fail. In general, you should not update the cookie specification once an application is in production. If you do, mutliple cookies with the same name will be saved back to the browser and will be sent back to your application, which will undoubtably cause deserialization of the session cookie to fail. Here are some general recomendations on how to configure cookie session cookie, either with the plugin's configuration options or with the SessionCookieConfig:

\n\n

Logging

\n

The following logback keys are configurable:

\n\n

Configured Beans

\n\n

How this plugin works

\n

This plugin consists of the following components:

\n\n

Execution sequence outline

\n

When a request is received by the server, the CookieSessionFilter is called in the filter chain and performs the following:

\n
    \n
  1. retrieves an instance of a SessionRepository bean from the application context
  2. \n
  3. creates an instance of the SessionRepositoryRequestWrapper, assigning it the SessionRepository instance and the current request
  4. \n
  5. uses SessionRepositoryRequestWrapper instance to restore the session
  6. \n
  7. uses the SessionRepositoryInstance to get the current session
  8. \n
  9. creates an instance of the SessionRepositoryResponseWrapper, assigning it the current session, the SessionRespository instance and the current response object.
  10. \n
  11. calls the next filter in the chain
  12. \n
\n

Throughout the remainder of the request, the SessionRepositoryRequestWrapper is only responsible for returning the stored instances of the SerializableSession.

\n

As the request processing comes to a conclussion the SessionRepositoryResponseWrapper is used to intercept calls that would cause the response to be committed (i.e. written back to the client). When it intercepts these calls, it uses a SessionRepository object to persist the Session object.

\n

The CookieSession object is a spring bean that implements the SessionRepository interface. This object is injected injected into the application so that it can be replaced with alternative implementations that can store the session to different locations such as database, shared in-memory store, shared filesystem, etc.

\n

How to contribute

\n

If you want to contribute a bug fix, please work from the 'develop' branch. Additionally, before submitting a pull request please confirm that all of the tests in test suite pass. The test suite is located at github.com/benlucchesi/test-cookie-session-plugin

\n" }, { "bintrayPackage": { "name": "cookie-session", "repo": "plugins", "owner": "double16", "desc": "The Cookie Session plugin enables grails applications to store session data in http cookies between requests instead of in memory on the server.", "labels": [ "cookies", "http-session" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/double16/grails-cookie-session/issues", "latestVersion": "4.0.2", "updated": "2018-07-18T13:04:38.683Z", "systemIds": [ "org.grails.plugins:cookie-session" ], "vcsUrl": "https://github.com/double16/grails-cookie-session.git" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Cookie Session Grails Plugin

\n

\"Download\" \"CircleCI\"

\n

The Cookie Session plugin enables grails applications to store session data in http cookies between requests instead of in memory on the server. Client sessions are transmitted from the browser to the application with each request and transmitted back with each response. This allows application deployments to be more stateless. Benefits of managing sessions this way include:

\n

Simplified Scaling

\n

Because a client's session is passed with every request, the deployment architecture need not be concerned with scaling strategies that account for sessions stored on the server, such as session replication or sticky sessions. Simply add application instances and route requests to them. Also, because the session data is stored with client, the server doesn't expend memory or disk space storing sessions that are open for long periods of time.

\n

Fault Tolerance

\n

When sessions are stored in memory on the server, if an application crashes or becomes inaccessible, clients' sessions are usually lost which can result in unexpected logout, redirects, or loss of data. When sessions are stored cookies,the applications can be much more tolerant to server-side commission failures. In a single-instance deployment scenario, the server or application can be recycled and clients can continue working when the application becomes available and with their session fully intact. In a multi-instance deployment scenario, any instance of the application can service a clients request. A beneficial side effect of cookie-sessions is that applications can be upgraded or restarted without logging out users.

\n\n

Installation

\n

Edit build.gradle add the following line under the plugins closure

\n
  compile 'org.grails.plugins:cookie-session:4.0.2'\n
\n

Configuration

\n

The following parameters are supported directly by the cookie-session plugin. Note, additional configuration is needed for large session support. See additional instructions below.

\n

Parameters

\n

| name | default | description |\n| ---- | ------- | ----------- |\n| grails.plugin.cookiesession.enabled | false | enables or disables the cookie session. |\n| grails.plugin.cookiesession.encryptcookie | true | enable or disable encrypting session data stored in cookies. |\n| grails.plugin.cookiesession.cryptoalgorithm | Blowfish | The cryptographic algorithm used to encrypt session data (i.e. Blowfish, DES, DESEde, AES). NOTE: the secret must be compatible with the crypto algorithm. Version 2.0.12 supports non-ECB cipher modes, such as 'Blowfish/CBC/PKCS5Padding', that require an initialization vector |\n| grails.plugin.cookiesession.secret | generated | The secret key used to encrypt session data. If not set, a random key will be created at runtime. Set this parameter if deploying multiple instances of the application or if sessions need to survive a server crash or restart. sessions to be recovered after a server crash or restart. |\n| grails.plugin.cookiesession.cookiecount | 5 | The maximum number of cookies that are created to store the session in |\n| grails.plugin.cookiesession.maxcookiesize | 2048 | The max size for each cookie expressed in bytes. |\n| grails.plugin.cookiesession.warnthreshold | 0.8 | Threshold for logging a warning when the cookie size becomes equal to or greater than the total maximum cookie size (cookieCount * maxCookieSize) |\n| grails.plugin.cookiesession.sessiontimeout | 0 | The length of time a session can be inactive for expressed in seconds. -1 indicates that a session will be active for as long as the browser is open. |\n| grails.plugin.cookiesession.cookiename | gsession-X | X number of cookies will be written per the cookiecount parameter. Each cookie is suffixed with the integer index of the cookie. |\n| grails.plugin.cookiesession.condenseexceptions | false | replaces instances of Exceptions objects in the session with the Exception.getMessage() in the session (see SessionPersistanceListener for further details) |\n| grails.plugin.cookiesession.serializer | 'java' | specify serializer used to serialize session objects. valid values are: 'java', 'kryo', or the name of a spring bean that implement SessionSerializer. See section on Serializers below. |\n| grails.plugin.cookiesession.usesessioncookieconfig | false | version 2.0.12+ uses the ServletContext.SessionCookieConfig to configure cookies used to store the session. values from SessionCookieConfig override config parameters setsecure, sethttp, path, domain, comment, sessiontimeout, and cookiename. See notes below on use of this config option. |\n| grails.plugin.cookiesession.springsecuritycompatibility | false | true to configure enhanced compatibility with spring security, false to disable. |\n| grails.plugin.cookiesession.setsecure | false | calls Cookie.setSecure on cookie-session cookies. This flag indicates to browsers whether cookies should only be sent over secure connections. |\n| grails.plugin.cookiesession.httponly | false | calls Cookie.setHttpOnly on cookie-session cookies. This flag indicates to browsers that the cookie should not be made available to scripts. |\n| grails.plugin.cookiesession.path | / | calls Cookie.setPath on cookie-session cookies. This limits the paths for which the browser should send the cookie. |\n| grails.plugin.cookiesession.domain | -unset- | calls Cookie.setDomain on cookie-session cookies if set. This tells the browsers which domains the cookie is valid for; if unset, then the cookie is valid for the current host only. |\n| grails.plugin.cookiesession.comment | -unset- | calls Cookie.setComment on cookie-session cookies. |\n| grails.plugin.cookiesession.id | deprecated | deprecated. use the 'grails.plugin.cookiesession.cookiename' setting. |\n| grails.plugin.cookiesession.timeout | deprecated | deprecated. use the 'grails.plugin.cookiesession.sessiontimeout' setting. |\n| grails.plugin.cookiesession.hmac.secret | deprecated | deprecated. use the 'grails.plugin.cookiesession.secret' setting. |\n| grails.plugin.cookiesession.hmac.id | deprecated | deprecated. no equivalent setting is present in this version of the plugin. |\n| grails.plugin.cookiesession.hmac.algorithm | deprecated | deprecated. use the 'grails.plugin.cookiesession.cryptoalgorithm' settings. |

\n

Example

\n

application.yml

\n
grails:\n  plugin:\n    cookiesession:\n      enabled: true\n      encryptcookie: true\n      cryptoalgorithm: "Blowfish"\n      secret: "This is my secret."\n      cookiecount: 10\n      maxcookiesize: 2048  // 2kb\n      sessiontimeout: 3600 // one hour\n      cookiename: 'gsession'\n      condenseexceptions: false\n      setsecure: true\n      httponly: false\n      path: '/'\n      comment: 'Acme Session Info'\n      serializer: 'kryo'\n      springsecuritycompatibility: true\n
\n

Understanding cookiecount and maxcookiesize

\n

The maximum session size stored by this plugin is calculated by (cookiecount * maxcookiesize). The reason for these two parameters is that through experimentation, some browsers didn't reliably set large cookies set before the subsequent request. To solve this issue, this plugin supports configuring the max size of each cookie stored and the number of cookies to span the session over. The default values are conservative. If sessions exceed the max session size as configured, first increase the cookiecount and then the maxcookiesize parameters.

\n

Enabling large session

\n

To enable large sessions, increase the max http header size for the servlet container you are using.

\n

Due to the potentially large amount of data that may be stored, consider setting it to something large, such as 262144 ( 256kb ).

\n

the following are for grails 2.x, needs to be updated for 3.x - investigating

\n

Tomcat

\n

Edit the server.xml and set the connector's maxHttpHeaderSize parameter.

\n

When developing in grails, configure the embedded tomcat server with the tomcat configuration event:

\n
    \n
  1. \n

    create the file scripts/_Events.groovy in your project directory

    \n
  2. \n
  3. \n

    add the following code:

    \n
    eventConfigureTomcat = {tomcat ->\n  tomcat.connector.setAttribute("maxHttpHeaderSize",262144)\n}\n
    \n
  4. \n
\n

Jetty (2.0.5+)

\n

Edit the jetty.xml or web.xml and set the connector's requestHeaderSize and responseHeaderSize parameters.

\n
    \n
  1. \n

    create the file scripts/_Events.groovy in your project directory

    \n
  2. \n
  3. \n

    add the following code:

    \n
    eventConfigureJetty = {jetty ->\n  jetty.connectors[0].requestHeaderSize = 262144\n  jetty.connectors[0].responseHeaderSize = 262144\n}\n
    \n
  4. \n
\n

SessionPersistenceListener

\n

SessionPersistenceListener is an interface used inspect the session just after its been deserialized from persistent storage and just before being serialized and persisted.

\n

SessionPersistenceListener defines the following methods:

\n
    void afterSessionRestored( SerializableSession session )\n    void beforeSessionSaved( SerializableSession session )\n
\n

To use, write a class that implements this interface and define the object in the application's spring application context (grails-app/conf/spring/resources.groovy). The CookieSession plugin will scan the application context and retrieve references to all classes that implement SessionPersistenceListener. The order that the SessionPersistenceListeners are called is unspecified. For an example of how to implement a SessionPersistenceListener, see the ExceptionCondenser class which is part of the cookie-session plugin.

\n

The ExceptionCondenser uses beforeSessionSaved() to replace instances of Exceptions the exception's message. This is useful because some libraries, notably the spring-security, store exceptions in the session, which can cause the cookie-session storage to overflow. The ExceptionCondenser can be installed by either adding it in the application context or by enabling it with the convenience settings grails.plugin.cookiesession.condenseexceptions = true.

\n

Configuring Serialization

\n

The grails.plugin.cookiesession.serializer config setting is used to pick which serializer the cookie-session plugin will use to serialize sessions. Currently, only two options are supported: 'java' and 'kryo'. 'java' is used to pick the java.io API serializer. This serializer has proven to be reliable and works 'out of the box'. 'kryo' is used to pick the Kryo serializer (https://github.com/EsotericSoftware/kryo). The Kryo serializer has many benefits over the Java serializer, primarily serialized results are significantly smaller which reduces the size of the session cookies. However, the Kryo serializer requires configuration to work correctly with some grails and spring objects. By default the kryo serializer is configured to serialize GrailsFlashScope and other basic grails objects. If the application uses spring-security, you must enable springsecuritycompatibility for the cookie-session plugin. Additionally you should verify that the serializer is successfully serializing all objects that will be stored in the session. Configure info level logging for grails.plugins.cookiesession.CookieSessionRepository for test and development environments to monitor the serialization and deserialization process. If objects fail to serialize, please report an issue to this github project; a best effort will be made to make the kryo serializer as compatible as possible. If the kryo serializer doesn't work for your application, consider falling back to the java serializer or implementing your own SessionSerializer as described below.

\n

Spring Security Compatibility

\n

Spring Security Compatibility, configured with the springsecuritycompatibility setting, directs the cookie-session plugin to adjust its behavior to be more compatible with the spring-security-core plugin.

\n

The primary issue addressed in this mode relates to when the spring-security core's SecurityContextPersistenceFilter writes the current security context to the SecurityContextRepository. In most cases, the SecurityContextPersistenceFilter stores the current security context after the current web response has been written. This is a problem for the cookie-session plugin because the session is stored in cookies in the web response. As a result, the current security context is never saved in the session, in effect losing the security context after each request. To work around this issue, spring security compatibility mode causes the cookie-session plugin to write the current security context to the session just before the session is serialized and saved in cookies. The security context is stored under the key that the SecurityContextRepository expects to find the security context.

\n

The next issue that Spring Security Compatibility addresses involves cookies saved in the DefaultSavedRequest. DefaultSavedRequest is created by spring security core and stored in the session during redirects, such as after authentication. Spring Security Compatibility causes the cookie-session plugin to detect the presence of a DefaultSavedRequest in the session and remove any cookie-session cookies it may be storing. This ensures that old session information doesn't replace more current session information when following a redirect. This also reduces the size of the the serialized session because the DefaultSavedRequest is storing an old copy of a session in the current session.

\n

Finally, Spring Security Compatibility adds custom kryo serializers (when kryo serialization is enabled) to successfully serialize objects that kryo isn't capable of serializing by default.

\n

When compatibility with Spring Security is enabled the plugin may enforce new session creation if none exists yet. The reason is that without a session present the Security Context would not be persisted and propagated between requests. This would manifest as an intermittent issue depending whether or not the application uses session for some other purpose or not (e.g. flash scope).

\n

use of SessionCookieConfig

\n

SessionCookieConfig is a interface introduced in Servlet 3.0 and is used to specify configuration parameters of session cookies. If you enable the grails.plugin.cookiesession.usesessioncookieconfig parameter, then this interface is used to configure the cookie session cookies. In order for this option to work, the servlet context must be servlet context version 3.0 or great.

\n

The following is an example of how to use the SessionCookieConfig to configure cookies in the init closure in BootStrap.groovy.

\n
        if( servletContext.majorVersion >= 3 ){\n          servletContext.sessionCookieConfig.name = 'sugar2'\n          servletContext.sessionCookieConfig.secure = false\n          servletContext.sessionCookieConfig.maxAge = 3600\n        }\n
\n

WARNING on updating cookie specifications and general recommendations

\n

Be warned, updating the cookie specification can cause unexpected results and cause your application to fail. In general, you should not update the cookie specification once an application is in production. If you do, multiple cookies with the same name will be saved back to the browser and will be sent back to your application, which will undoubtedly cause deserialization of the session cookie to fail. Here are some general recommendations on how to configure cookie session cookie, either with the plugin's configuration options or with the SessionCookieConfig:

\n\n

Logging

\n

The following logback keys are configurable:

\n\n

Configured Beans

\n\n

How this plugin works

\n

This plugin consists of the following components:

\n\n

Execution sequence outline

\n

When a request is received by the server, the CookieSessionFilter is called in the filter chain and performs the following:

\n
    \n
  1. retrieves an instance of a SessionRepository bean from the application context
  2. \n
  3. creates an instance of the SessionRepositoryRequestWrapper, assigning it the SessionRepository instance and the current request
  4. \n
  5. uses SessionRepositoryRequestWrapper instance to restore the session
  6. \n
  7. uses the SessionRepositoryInstance to get the current session
  8. \n
  9. creates an instance of the SessionRepositoryResponseWrapper, assigning it the current session, the SessionRepository instance and the current response object.
  10. \n
  11. calls the next filter in the chain
  12. \n
\n

Throughout the remainder of the request, the SessionRepositoryRequestWrapper is only responsible for returning the stored instances of the SerializableSession.

\n

As the request processing comes to a conclusion the SessionRepositoryResponseWrapper is used to intercept calls that would cause the response to be committed (i.e. written back to the client). When it intercepts these calls, it uses a SessionRepository object to persist the Session object.

\n

The CookieSession object is a spring bean that implements the SessionRepository interface. This object is injected injected into the application so that it can be replaced with alternative implementations that can store the session to different locations such as database, shared in-memory store, shared filesystem, etc.

\n

How to contribute

\n

If you want to contribute a bug fix, please work from the 'develop' branch. Additionally, before submitting a pull request please confirm that all of the tests in test suite pass. The test suite can be run using gradlew check testAll integrationTestAll

\n" }, { "bintrayPackage": { "name": "csrf", "repo": "grails-csrf-plugin", "owner": "matrei", "desc": "CSRF Protection for Grails", "labels": [ "csrf", "security" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/matrei/grails-csrf-plugin/issues", "latestVersion": "1.0.0", "updated": "2024-04-30T11:17:36.000Z", "systemIds": [ "io.github.matrei:grails-csrf" ], "vcsUrl": "https://github.com/matrei/grails-csrf-plugin" }, "documentationUrl": "https://github.com/matrei/grails-csrf-plugin#readme", "mavenMetadataUrl": "https://repo1.maven.org/maven2/io/github/matrei/grails-csrf/maven-metadata.xml" }, { "bintrayPackage": { "name": "csv", "repo": "plugins", "owner": "sachinverma", "desc": "Grails csv plugin", "labels": [ "csv" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/vsachinv/grails-csv/issues", "latestVersion": "1.0.1", "updated": "2018-02-23T07:25:16.181Z", "systemIds": [ "org.grails.plugins:csv" ], "vcsUrl": "https://github.com/vsachinv/grails-csv" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

grails-csv

\n

The csv plugin provides utility methods and also support for reading/writing to csv files. It uses opencsv library.

\n

Installation

\n

Add dependency to your build.gradle for Grails 3.x:

\n
repositories {\n  ...\n  maven { url "http://dl.bintray.com/sachinverma/plugins" }\n}\n\ndependencies {\n    compile 'org.grails.plugins:grails-csv:1.0.1'\n}\n
\n

For further info: [https://github.com/vsachinv/grails-csv/wiki/Grails-CSV]

\n" }, { "bintrayPackage": { "name": "cxf", "repo": "grails-plugins", "owner": "ctoestreich", "desc": "Grails CXF Plugin", "labels": [ "cxf", "soap" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/Grails-Plugin-Consortium/grails-cxf/issues", "latestVersion": "3.1.2", "updated": "2018-05-04T00:36:38.345Z", "systemIds": [ "org.grails.plugins:cxf", "org.grails.plugins:grails-cxf" ], "vcsUrl": "https://github.com/Grails-Plugin-Consortium/grails-cxf" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

\"Build

\n

\n

The docs for the 2.x branch can be found here. A lot of the previous documentation is somewhat applicable, but I will be creating new docs in the coming weeks.

\n

Grails CXF Plugin

\n

The 3.x branch of the plugin is a grails plugin that contains simplified features to get simple soap endpoints exposed in grails 3 applications.

\n

Getting Started

\n

At the core, this plugin is a simple wrapper for geeting grails service classes wired up as direct soap endpoints. As many of the previous features from the 2.x branch as could be ported for the initial release were ported. There will be continued support added for the more complex CXF features going forward.

\n

Basic Usage

\n

Exposing a service class is as simple as adding the GrailsCxfEndpoint annotation and annotating the methods you wish to expose in the service with WebMethod and WebResult

\n
package com.gpc.demo\n\nimport grails.transaction.Transactional\nimport org.grails.cxf.utils.GrailsCxfEndpoint\n\nimport javax.jws.WebMethod\nimport javax.jws.WebResult\n\n@Transactional\n@GrailsCxfEndpoint\nclass DemoService {\n\n    @WebMethod\n    @WebResult\n    String demoMethod() {\n        return "demo"\n    }\n}\n
\n

Returning Domain Classes

\n

If you wish to return domain classes you will need to make sure to add the xml annotations to the domain class.

\n
package org.grails.cxf.test.example\n\nimport grails.transaction.Transactional\nimport org.grails.cxf.utils.GrailsCxfEndpoint\n\nimport javax.jws.WebMethod\nimport javax.jws.WebParam\nimport javax.jws.WebResult\n\n@Transactional\n@GrailsCxfEndpoint\nclass PersonService {\n\n\t@WebMethod\n\t@WebResult(name = "Person", targetNamespace = "")\n\tPerson createPerson(@WebParam(name = 'name') String name) {\n\t\tPerson.findOrSaveByName(name)\n\t}\n}\n
\n
package org.grails.cxf.test.example\n\nimport javax.xml.bind.annotation.XmlAccessType\nimport javax.xml.bind.annotation.XmlAccessorType\nimport javax.xml.bind.annotation.XmlElement\n\n@XmlAccessorType(XmlAccessType.NONE)\nclass Person {\n\n    @XmlElement\n    Long id\n\n    @XmlElement\n    String name\n\n    static constraints = {\n        name nullable: false, blank: false\n    }\n}\n
\n

Custom Interceptors

\n

Do add a custom interceptor you should define an bean in your application or imported config class. The reference to the logging interceptor is the name of the defined bean.

\n
package org.grails.cxf.test.soap.interceptor\n\nimport org.apache.cxf.common.injection.NoJSR250Annotations\nimport org.apache.cxf.common.logging.LogUtils\nimport org.apache.cxf.interceptor.AbstractLoggingInterceptor\nimport org.apache.cxf.interceptor.Fault\nimport org.apache.cxf.message.Message\nimport org.apache.cxf.phase.Phase\nimport org.springframework.beans.factory.annotation.Autowired\n\nimport java.util.logging.Logger\n\n/**\n */\n@NoJSR250Annotations\nclass CustomLoggingInInterceptor extends AbstractLoggingInterceptor {\n\n    private static final Logger LOG = LogUtils.getLogger(CustomLoggingInInterceptor)\n    def name\n\n    CustomLoggingInInterceptor() {\n        super(Phase.RECEIVE)\n        log LOG, 'Creating the custom interceptor bean'\n    }\n\n    void handleMessage(Message message) throws Fault {\n        //get another web service bean here by name and call it\n\n        //Check to see if cxf annotations will inject the bean (looks like no!)\n        log LOG, injectedBean?.name ?: 'FAIL - NOT SET'\n        log LOG, "$name :: I AM IN CUSTOM IN LOGGER!!!!!!!"\n    }\n\n    @Override\n    protected Logger getLogger() {\n        LOG\n    }\n}\n
\n
package grails.cxf.demo\n\nimport grails.boot.GrailsApp\nimport grails.boot.config.GrailsAutoConfiguration\nimport org.grails.cxf.test.soap.interceptor.CustomLoggingInInterceptor\nimport org.springframework.context.annotation.Bean\nimport org.springframework.context.annotation.ImportResource\n\nclass Application extends GrailsAutoConfiguration {\n    static void main(String[] args) {\n        GrailsApp.run(Application, args)\n    }\n\n    @Bean\n    public CustomLoggingInInterceptor customLoggingInInterceptor(){\n        return new CustomLoggingInInterceptor(name: 'injected value')\n    }\n}\n
\n
package org.grails.cxf.test.example\n\nimport grails.transaction.Transactional\nimport org.grails.cxf.utils.GrailsCxfEndpoint\n\nimport javax.jws.WebMethod\nimport javax.jws.WebParam\nimport javax.jws.WebResult\n\n@Transactional\n@GrailsCxfEndpoint(inInterceptors = ['customLoggingInInterceptor'])\nclass PersonService {\n\n\t@WebMethod\n\t@WebResult(name = "Person", targetNamespace = "")\n\tPerson createPerson(@WebParam(name = 'name') String name) {\n\t\tPerson.findOrSaveByName(name)\n\t}\n}\n
\n

SERVLET MAPPING

\n

The default behavior is to expose the CxfServlet at the /services/* endpoint. If you with to override this behavior you can set the following config:

\n
cxf:\n    servlet:\n        mapping: /webservices/*\n
\n

EXPOSING CLASSES VIA ANNOTATION

\n

When using the annotation, the property values will only be used if the corresponding annotation value is not provided or is set to the default value. The following are available to configure via the annotation:

\n
/**\n * Annotation to be use to expose a Service or Endpoint class as a CXF Service via Grails.\n */\n@Retention(RetentionPolicy.RUNTIME)\n@Target(ElementType.TYPE)\n@interface GrailsCxfEndpoint {\n    String address() default ''\n    String name() default ''\n    EndpointType expose() default EndpointType.JAX_WS\n    boolean soap12() default false\n    String wsdl() default ''\n    //Interceptors\n    String[] inInterceptors() default []\n    String[] outInterceptors() default []\n    String[] inFaultInterceptors() default []\n    String[] outFaultInterceptors() default []\n    GrailsCxfEndpointProperty[] properties() default []\n}\n\n@Target(ElementType.METHOD)\n@interface GrailsCxfEndpointProperty {\n    public String name() default ''\n    public String value() default ''\n}\n\n
\n

ADDRESS

\n

The address property is used to adjust the endpoint address that the service will be deployed to. By default if not provided or is the value is empty (""), this will be the name of the Service or Endpoint with the first letter lowercase and the word Endpoint or Service removed from the end of the name. The default behavior would deploy the BoatService as /services/boat.

\n

If you wish to override this and provide your own service name or address (for versioning support for example) you may set this value.

\n
@GrailsCxfEndpoint(address='/v2/custom/path')\nclass CarService {\n    ...\n}\n
\n

The above would be deployed to /services/v2/custom/path.

\n

EXPOSE

\n

The expose property will tell the plugin how you wish to expose. The default is EndpointType.JAX_WS which is the same as the following:

\n
@GrailsCxfEndpoint(expose=EndpointType.JAX_WS)\nclass CarService {\n    ...\n}\n
\n

Simple and JaxRS types are currently not supported. TODO

\n

NAME

\n

The name property will tell the plugin how you wish to name the service. This will change the wsdl name property from the default for the example below from CarService to simply just Car like this <wsdl:definitions name="Car" targetNamespace="http://demo.gpc.com">

\n
@GrailsCxfEndpoint(name='Car')\nclass CarService {\n    ...\n}\n
\n

PORT

\n

The port property will tell the plugin how you wish to name the service port binding. This will change the wsdl name property of the port from the default for the example below from CarServicePort to simply just CarPort like this <wsdl:port binding="tns:CarServiceSoapBinding" name="CarPort">

\n
@GrailsCxfEndpoint(port='CarPort')\nclass CarService {\n    ...\n}\n
\n

SOAP12

\n

To tell a service to default to SOAP 1.2 instead of 1.1 simply set this to true. The default value is false which will use SOAP 1.1.

\n
@GrailsCxfEndpoint(soap12=true)\nclass CarService {\n    ...\n}\n
\n

WSDL

\n

To expose as a wsdl first jax web service endpoint http://cxf.apache.org/docs/jax-ws-configuration.html add the wsdl property and classpath to the wsdl as well as setting the endpoint type to EndpointType.JAX_WS_WSDL.

\n
@WebService(name = 'CustomerServiceWsdlEndpoint',\ntargetNamespace = 'http://test.cxf.grails.org/',\nserviceName = 'CustomerServiceWsdlEndpoint',\nportName = 'CustomerServiceWsdlPort')\n@GrailsCxfEndpoint(wsdl = 'org/grails/cxf/test/soap/CustomerService.wsdl', expose = EndpointType.JAX_WS_WSDL)\nclass AnnotatedCustomerServiceWsdlEndpoint {\n\n    CustomerServiceEndpoint customerServiceEndpoint\n\n    List<Customer> getCustomersByName(final String name) {\n        customerServiceEndpoint.getCustomersByName(name)\n    }\n}\n
\n

Example TODO

\n

\nININTERCEPTORS

\n

This is a list of bean names in List<String> to inject to the cxf service endpoint. You will need to define your interceptor beans via normal spring dsl (in resources.groovy for example).

\n

This is helpful when the default cxf annotation of @org.apache.cxf.interceptor.InInterceptors (interceptors = {"com.example.Test1Interceptor" }) does not satisfy your needs.

\n

When chosing between the this property and the cxf provided one, if you require value injection, the cxf provided annotation will most likely NOT meet your needs and you should use this property instead.

\n

Note: Make sure to set any beans you wish injected into your interceptors to bean.autowire = 'byName' or use the @Autowire annotation.

\n

OUTINTERCEPTORS

\n

If you wish to inject a custom in interceptor bean, use this property. This is helpful when the default cxf annotation of @org.apache.cxf.interceptor.OutInterceptors (interceptors = {"com.example.Test1Interceptor" }) does not satisfy your needs.

\n

See above for examples of using inInterceptor which should be very similar.

\n

INFAULTINTERCEPTORS

\n

If you wish to inject a custom in interceptor bean, use this property. This is helpful when the default cxf annotation of @org.apache.cxf.interceptor.InFaultInterceptors (interceptors = {"com.example.Test1Interceptor" }) does not satisfy your needs.

\n

See above for examples of using inInterceptor which should be very similar.

\n

OUTFAULTINTERCEPTORS

\n

If you wish to inject a custom in interceptor bean, use this property. This is helpful when the default cxf annotation of @org.apache.cxf.interceptor.OutFaultInterceptors (interceptors = {"com.example.Test1Interceptor" }) does not satisfy your needs.

\n

See above for examples of using inInterceptor which should be very similar.

\n

CONCLUSION

\n

Using the annotation will help reduce the clutter of having many static properties in your class to configure cxf.

\n

Demo Project

\n

https://github.com/Grails-Plugin-Consortium/grails-cxf-demo

\n

Top

\n\nLICENSE\n---------------\n

Copyright 2013 Christian Oestreich

\n

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

\n

http://www.apache.org/licenses/LICENSE-2.0

\n

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

\n" }, { "bintrayPackage": { "name": "cxf-client", "repo": "grails-plugins", "owner": "ctoestreich", "desc": "Grails CXF Client Plugin", "labels": [ "cxf", "soap", "client" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/Grails-Plugin-Consortium/grails-cxf-client/issues", "latestVersion": "3.0.7", "updated": "2016-04-11T19:21:38.732Z", "systemIds": [ "org.grails.plugins:cxf-client", "org.grails.plugins:grails-cxf-client" ], "vcsUrl": "https://github.com/Grails-Plugin-Consortium/grails-cxf-client" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": null }, { "bintrayPackage": { "name": "database-migration", "repo": "plugins", "owner": "grails", "desc": "Grails database-migration plugin", "labels": [ "liquibase", "migration", "database" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails/grails-database-migration/issues", "latestVersion": "4.2.1", "updated": "2023-08-31T03:18:31.000Z", "systemIds": [ "org.grails.plugins:database-migration" ], "vcsUrl": "https://github.com/grails/grails-database-migration" }, "documentationUrl": "https://grails.github.io/grails-database-migration/", "mavenMetadataUrl": "https://repo1.maven.org/maven2/org/grails/plugins/database-migration/maven-metadata.xml", "readme": null }, { "comment": "There is no published version that is compatible with Grails >= 3 (0.3 is not published as of this writing)", "bintrayPackage": { "name": "daysofweek", "repo": "daysofweek", "owner": "vahid", "desc": "Grails Days Of week plugin using ICU4J libraries to work out international calendar week days", "labels": [ "calendar" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/vahidhedayati/grails-daysofweek-plugin/issues", "latestVersion": "0.2", "updated": "2019-05-17T13:10:27.982Z", "systemIds": [ "org.grails.plugins:daysofweek" ], "vcsUrl": "https://github.com/vahidhedayati/grails-daysofweek-plugin" }, "documentationUrl": "https://vahidhedayati.github.io/grails-daysofweek-plugin/", "mavenMetadataUrl": null, "readme": "

daysofweek

\n

Side note - similar / related projects

\n\n

Grails Days Of week plugin using ICU4J libraries to work out internationl calendar week days

\n

Dependency Grails 2:

\n
\tcompile ":daysofweek:0.1"\n
\n

Grails 2 source

\n

Dependency Grails 3 (build.gradle):

\n
\tcompile "org.grails.plugins:daysofweek:0.3"\n
\n

Grails 3 source

\n

Documentation

\n

Class usages

\n

\"sample

\n

daysofweek provides a bootstrap and jquery-ui method of showing the actual days output, depending on which you prefer or already have installed

\n

The plugin without being wired back into validation bean will return a list of selected days of the week by end user\nby default bindToBean is disabled is won't bind to the bean, this needs to be set to true to get it internal validation bean to pickup calculate. Only 1 element on a given form within gsp can bind to the bean. The rest will need to follow this method. Please refer to example below for a better insight.

\n

To get a final value which this plugin converts to / from you need to run:\nByte dow = DaysOfWeek.fromListToBit(params.list('daysOfWeek'))

\n

This return a byte value of dow which contains which week days the end user has selected. When this is stored and reloaded in the context of above bean it will show the days as per selection.

\n

Using plugin:

\n

Simply call <dow:week ....{below options} /> :

\n

This will return as above your own fieldName as the params back or by default as above daysOfWeek which contains a 'Byte' value which represents the bitwise value of the week days the end user has selected.

\n

Simply wire in that same byte value back into same tag lib and set dow to be that value for the plugin to draw out the selected days of the week user selected previously.

\n
dow="${myDow}"       = The byte value if already provided from db or something\ndow="${64 as Byte}"  = you setting byte value manually this then populates relevant days.\n\ndaysOfweek="${['SUN','MON','TUE','WED','THU','FRI','SAT']}"  = either provide the dow above \n\t\t\t\t\t\tor physical a list of a selection of  day names as shown\n\n\ncontext="section2"   = Not needed if called only once on page, this is so that js stuff works per call \n \nshowLocale="${true}" = To show the locale in showLabel only works if showLabel is on\n\nshowLabel="${true}"  = Show week days label and if showLocale true also shows locale\n\nfieldName="myDow"    = This is the variable name of your checkbox by default daysOfWeek \n\nlocale="${new Locale("ar","IQ")}"  = Override system locale to show which ever order of days of week\n\t\t\t\t\tPlease note this only overrides the ordering sequence of days and not actual screen\n\t\t\t\t\t text which is done via  ?lang=th lang parameter on url line.\n\t\t\t\t\t \n template="/some/path/to/gsp/template/_override_plugin.gsp"   =This is to override the template to your\n \t\t\t\t\t\t own custom template if you so wish not to use plugin method of display days etc.\n \n bindToBean="${true}"  = This by default is false if set to true one one <dow:week on a given page \n \t\t\t\t\t\tcan auto bind to backend bean as per controllers above.\n \n activateAll="${true}" =this is by defaut false, if there is currently no value provided and there \n \t\t\t\t\t\tare no active selected days, it attempts to pre-select all days for form loading up. \n \t\t\t\t\t\tYou may wish for it to show everything as active as page starts up\n\n
\n

Example controller/views: How to use daysofweek

\n

Youtube video demonstrating plugin

\n

Points of reference

\n

Info behind weekdays byte value stackoverflow link

\n" }, { "bintrayPackage": { "name": "db-reverse-engineer", "repo": "plugins", "owner": "grails", "desc": "Grails db-reverse-engineer plugin", "labels": [ "database" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails-plugins/grails-db-reverse-engineer/issues", "latestVersion": "4.0.0", "updated": "2017-01-26T14:03:06.363Z", "systemIds": [ "org.grails.plugins:db-reverse-engineer" ], "vcsUrl": "https://github.com/grails-plugins/grails-db-reverse-engineer" }, "documentationUrl": "https://grails-plugins.github.io/grails-db-reverse-engineer/", "mavenMetadataUrl": null, "readme": null }, { "displayName": "oauth", "bintrayPackage": { "name": "desirableobjects.grails.plugins:oauth", "repo": "grails-plugins", "owner": "desirable-objects", "desc": "Grails oauth plugin", "labels": [ "oauth" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/antony/grails-oauth-scribe/issues", "latestVersion": "4.0.0", "updated": "2017-05-17T21:16:51.385Z", "systemIds": [ "org.grails.plugins:oauth" ], "vcsUrl": "https://github.com/antony/grails-oauth-scribe" }, "documentationUrl": "https://antony.github.io/grails-oauth-scribe/", "mavenMetadataUrl": null, "readme": "

grails-oauth-scribe

\n

![Gitter](https://badges.gitter.im/Join Chat.svg)

\n" }, { "bintrayPackage": { "name": "distributed-lock", "repo": "grails3-plugins", "owner": "bertramlabs", "desc": "This plugin provides a framework and interface for a synchronization mechanism distributed to multiple server instances. In today's world of horizontal computational\nscale and massive concurrency, it becomes increasingly difficult to synchronize operations outside the context of a single computational space (server/process). This plugin aims to make that\neasier by providing a simple service to facilitate this, as well as defining an interface for adding low level providers.\n", "labels": [ "lock" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/bertramdev/distributed-lock/issues", "latestVersion": "4.0.11", "updated": "2022-10-05T00:17:57.274Z", "systemIds": [ "com.bertramlabs.plugins:distributed-lock" ], "vcsUrl": "https://github.com/bertramdev/distributed-lock" }, "documentationUrl": null, "mavenMetadataUrl": "https://repo1.maven.org/maven2/com/bertramlabs/plugins/distributed-lock/maven-metadata.xml", "readme": "

Grails Distributed Lock

\n

This plugin provides a framework and interface for a synchronization mechanism that can be distributed outside the context of the app container it runs in. In today's world of horizontal computational\nscale and massive concurrency, it becomes increasingly difficult to synchronize operations outside the context of a single computational space (server/process/container). This plugin aims to make that\neasier by providing a simple service to facilitate this, as well as defining an interface for adding low level providers.

\n

In the current release, only a provider for redis currently exists, which depends on the grails-redis plugin. Any other providers are welcome contributions.

\n

Release Notes

\n\n

Things to be Done

\n\n

Installation

\n

Add the plugin to your BuildConfig.groovy:

\n
plugins {\n\tcompile ":distributed-lock:0.1.0"\n}\n
\n

Configuration

\n

First thing is to configure your redis store. Add sample config to your Config.groovy:

\n
grails {\n\tredis {\n\t\thost = 'localhost'\n\t\tport = 6379\n\t}\n}\n
\n

NOTE: Please see grails-redis for more configuration details for your redis store

\n

Next, configure your distributed-lock options:

\n
distributedLock {\n\tprovider {\n\t\ttype = RedisLockProvider // Currently the only available provider\n\t\t// NOTE: Use only if not using the default redis connection\n\t\t// connection = 'otherThanDefault'\n\t}\n\traiseError = true //optional\n\tdefaultTimeout = 10000l //optional\n\tdefaultTTL = 1000l * 60l * 60l //optional (1 hour)\n\tnamespace = 'example-app' //optional\n}\n
\n

Configuration options:

\n\n

Usage

\n

The plugin provides a single non transactional service that handles all lock negotiation that you can inject in any of your services

\n
class MyService {\n\tdef lockService\n\t\n\tdef someMethod() {\n\t\tdef lockKey = lockService.acquireLock('/lock/a/shared/fs')\n\t}\n}\n
\n

LockService Methods

\n\n

Options

\n

The optional Map allows you to override certain configuration settings just for the context of your method call. Options include:

\n\n

Examples

\n

Simple usages of LockService:

\n
def lockKey = lockService.acquireLock('mylock')\n\t\nif (lockKey) {\n\t// Perform on operation we want synchronized\n}\nelse {\n\tprintln("Unable to obtain lock")\n}\n\t\n// try/finally to release lock\ntry {\n\tdef lock = lockService.acquireLock('lock2', [timeout:2000l, ttl:10000l, raiseError:false])\n\tif (lock) {\n\t\t// DO SOME SYNCHRONIZED STUFF\n\t}\n}\nfinally {\n\tlockService.releaseLock('lock2',[lock: lock])\n}\n
\n

Threaded sample using executor plugin:

\n
def lockService\n\t\n(0..10).each { i ->\n\trunAsync {\n\t\tdef lock\n\t\ttry {\n\t\t\tif (lock = lockService.acquireLock('test-run', [timeout:5000l]))\n\t\t\t\tprintln("Lock acquired for thread ${i}")\n\t\t\telse\n\t\t\t\tprintln("Failed to acquire lock for thread ${i}")\n\t\t\t\t\n\t\t\t// Sleep for random amount of time\n\t\t\tsleep(new Random().nextInt(1000) as Long)\n\t\t}\n\t\tfinally {\n\t\t\tlockService.releaseLock('test-run',[lock:lock])\n\t\t}\n\t}\n}\n
\n

Extending/Contributing

\n

To add additional providers is simple. Simply extend the abstract com.bertram.lock.LockProvider class and implement its abstract methods. Once the new provider is implemented, it must be added to the LockServiceConfigurer configuration method. Please submit contributions via pull request.

\n" }, { "bintrayPackage": { "name": "distributed-mutex", "repo": "grails-plugins", "owner": "budjb", "desc": "The Distributed Mutex plugin provides a way to create mutexes backed by a database row. This helps when writing distributed systems that need to lock a resource but database transactions are not sufficient to encapsulate the resource being accessed.", "labels": [ "lock" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/budjb/grails-distributed-mutex/issues", "latestVersion": "3.0.0", "updated": "2016-09-14T14:47:40.885Z", "systemIds": [ "org.grails.plugins:distributed-mutex" ], "vcsUrl": "https://github.com/budjb/grails-distributed-mutex" }, "documentationUrl": "https://budjb.github.io/grails-distributed-mutex/", "mavenMetadataUrl": null, "readme": "

\"Build

\n

Distributed Mutex Plugin for Grails

\n

See the documentation at http://budjb.github.io/grails-distributed-mutex/3.x/latest.

\n" }, { "displayName": "grails-simple-captcha", "bintrayPackage": { "name": "domurtag.plugins:grails-simple-captcha", "repo": "plugins", "owner": "domurtag", "desc": "Grails grails-simple-captcha plugin", "labels": [ "captcha" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/domurtag/grails-simple-captcha/issues", "latestVersion": "1.0.0-grails3", "updated": "2016-03-31T13:31:54.971Z", "systemIds": [ "domurtag.plugins:grails-simple-captcha" ], "vcsUrl": "https://github.com/domurtag/grails-simple-captcha" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

\"Build

\n

Summary

\n

Grails plugin that creates simple image CAPTCHAs that protect against automated completion and submission of HTML forms.

\n

Grails Versions

\n

Versions of this plugin that are compatible with Grails 1.X and 2.X are on the master branch. Grails 3.X compatible versions are on the grails3 branch. The first Grails 3 compatible version is 1.0.0-grails3.

\n

Description

\n

Overview

\n

A CAPTCHA is a small image that is embedded in a HTML form to protect against automated completion and submission of HTML forms.\nThey generally consist of an image of a short string of random characters visually obsfucated in some way (see wikipedia for more information).

\n

This plugin generates a small CAPTCHA image when the CaptchaController is invoked. The CAPTCHA image and it's solution is stored in the session by default,\nthough the pugin can be used without session storage if necessary. A typical example of the CAPTCHAs generated by this plugin is shown below.

\n

\"Example

\n

Why another CAPTCHA plugin?

\n

Although there is already a Grails plugin available for reCAPTCHA (a very popular CAPTCHA implementation), there are a number of differences between these two plugins:

\n\n

On the other hand, reCAPTCHA provides a number of features that are absent from this plugin, e.g. audio CAPTCHAs for those with impaired vision.

\n

Usage

\n

A CAPTCHA can be added to a form using the following GSP code

\n
<img src="${createLink(controller: 'simpleCaptcha', action: 'captcha')}"/>\n<label for="captcha">Type the letters above in the box below:</label>\n<g:textField name="captcha"/>\n
\n

As mentioned above, the CAPTCHAs generated by this plugin can be simultaneously displayed in several places on the same page\n(this is only possible with reCAPTCHA if you use JavaScript to clone the CAPTCHA).

\n

To check whether the solution to the CAPTCHA is correct:

\n
class MyController {\n  def simpleCaptchaService\n  // This is the action that handles the submission of the form with the CAPTCHA\n  def save = {\n    boolean captchaValid = simpleCaptchaService.validateCaptcha(params.captcha)   \n  }\n}\n
\n

The process of validating a CAPTCHA also removes it from the session, so it is only possible to validate each CAPTCHA once.\nThe CAPTCHA is removed from the seesion after validation to ensure that the next time a CAPTCHA is requested, a\ndifferent challenge will be presented.

\n

Configuration

\n

The plugin provides a number of optional configuration parameters that can be overriden in Config.groovy. The default\nvalues of these parameters are shown below:

\n
simpleCaptcha {\n    // font size used in CAPTCHA images\n    fontSize = 30\n    height = 200\n    width = 200\n    // number of characters in CAPTCHA text\n    length = 6\n\n    // amount of space between the bottom of the CAPTCHA text and the bottom of the CAPTCHA image\n    bottomPadding = 16\n\n    // distance between the diagonal lines used to obfuscate the text\n    lineSpacing = 10\n\n    // the charcters shown in the CAPTCHA text must be one of the following\n    chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"\n\n    // this param will be passed as the first argument to this java.awt.Font constructor\n    // http://docs.oracle.com/javase/6/docs/api/java/awt/Font.html#Font(java.lang.String,%20int,%20int)\n    font = "Serif"\n}\n
\n

Per-Locale Configuration

\n

The characters that are shown in the CAPTCHA can be configured per-locale. For example, if you want only the characters\n\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd \ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd to be shown by the CAPTCHA in the French locale, add the following to messages_fr.properties

\n
simpleCaptcha.chars=\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd \ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\n
\n

If a locale-specific configuration is found it will override the global configuration in Config.groovy

\n

Session Storage

\n

The plugin stores the CAPTCHA image and its solution in the session by default. If it is not feasible to use session storage,\nthe plugin can instead store a digest (hash) of the solution in a cookie. When a CAPTCHA solution is submitted, it is\nvalidated by comparing the digested solution with this cookie value. This option can be enabled simply by adding the\nfollowing config parameter:

\n
simpleCaptcha.storeInSession = false\n
\n

If session storage is disabled it is not possible to display a CAPTCHA in multiple places on the same page.

\n" }, { "displayName": "runtime-datasources", "bintrayPackage": { "name": "domurtag.plugins:runtime-datasources", "repo": "plugins", "owner": "domurtag", "desc": "Grails runtime-datasources plugin", "labels": [ "database" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/domurtag/runtime-datasources/issues", "latestVersion": "0.2-grails3", "updated": "2016-03-31T13:31:55.050Z", "systemIds": [ "domurtag.plugins:runtime-datasources" ], "vcsUrl": "https://github.com/domurtag/runtime-datasources" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

\"Build

\n

Introduction

\n

Grails plugin that enables an application to add or remove JDBC datasources at runtime, and provides convenience methods\nfor executing SQL statements against these datasources

\n

Versions

\n

Versions of this plugin that are compatible with Grails 2.X are on the master branch. Grails 3.X compatible versions are on the grails3 branch. The first Grails 3 compatible version is 0.2-grails3.

\n

Limitations

\n

GORM/Hibernate cannot be used with datasources added at runtime, because GORM requires the mapping between a domain\nclass and datasource to be defined at compile-time

\n

Add a DataSource

\n

Dependency-inject the runtimeDataSourceService service provided by the plugin and call it like so:

\n
import javax.sql.DataSource\nimport org.apache.tomcat.jdbc.pool.DataSource as JdbcDataSource\n\nDataSource runtimeDataSource = runtimeDataSourceService.addDataSource('myDataSource', JdbcDataSource) {\n    driverClassName = 'com.mysql.jdbc.Driver'\n    url = 'jdbc:mysql://localhost/example'\n    username = 'root'\n    password = 'password'\n}\n
\n

If successful, the method returns the created datasource.

\n

Arguments

\n
    \n
  1. The name of the Spring bean that will be registered for this datasource. If a Spring bean with this name already\nexists, an exception will be thrown
  2. \n
  3. Defines the implementation class of the Spring bean. This class must implement the javax.sql.DataSource interface.
  4. \n
  5. A closure that defines the properties of this datasource. At a minimum, the properties shown in the example above\nshould be provided. This closure supports the same properties as the closure that is used to set datasource properties\nat compile-time in DataSource.groovy
  6. \n
\n

Remove a DataSource

\n

The same service that is used to add datasources can also remove them:

\n
runtimeDataSourceService.removeDataSource('myDataSource')\n
\n

The argument should be the name of the datasource's Spring bean. The method returns true if the datasource was successfully\nremoved, or false if a datasource Spring bean with this name could not be found.

\n

Using a Runtime DataSource

\n

A reference to a DataSource instance added at runtime can be obtained in one of the following methods

\n
    \n
  1. The DataSource instance is returned upon creation (see examples above)
  2. \n
  3. The DataSource instance can also be retrieved from the Spring application context, e.g.
  4. \n
\n
class MyService implements ApplicationContextAware {\n\n    ApplicationContext applicationContext\n    \n    private DataSource getRuntimeDataSource(String beanName) {\n        \n        // the second parameter can be omitted\n        applicationContext.getBean(beanName, DataSource)\n    }\n}\n
\n

Executing SQL Against a Runtime DataSource

\n

Once you have obtained a reference to a DataSource using one of the methods outlined in the previous section, you\ncan construct a groovy.sql.Sql instance and use that to query/update\nthe datasource, e.g.

\n
class MyService implements ApplicationContextAware {\n\n    ApplicationContext applicationContext\n    \n    private executeSqlAgainstRuntimeDataSource(String beanName) {\n        \n        DataSource runtimeDataSource = applicationContext.getBean(beanName, DataSource)\n        Sql sql = new Sql(runtimeDataSource)\n        \n        try {\n            // use the Sql instance to execute a query, update data, etc.\n        } finally {\n            sql.close()\n        }\n    }\n}\n
\n

Alternatively, the aforementioned runtimeDataSourceService also provides a couple of convenience methods which makes\nthe process slightly simpler, e.g.

\n

Create Sql Instance

\n

The getSql method of the service slightly simplifies the process of creating the Sql instance for a runtime datasource.

\n
class MyService {\n\n    RuntimeDataSourceService runtimeDataSourceService\n    \n    private executeSqlAgainstRuntimeDataSource(String beanName) {\n        \n        Sql sql = runtimeDataSourceService.getSql(beanName)\n        \n        try {\n            // use the Sql instance to execute a query, update data, etc.\n        } finally {\n            sql.close()\n        }\n    }\n}\n```\n\n### Execute Query\n\nThe `doWithSql` method of the service simplifies the process of executing SQL statements against a datasource, e.g.\n\n````groovy\nclass MyService {\n\n    RuntimeDataSourceService runtimeDataSourceService\n    \n    private executeSqlAgainstRuntimeDataSource(String beanName) {\n        \n        Integer rowCount = runtimeDataSourceService.doWithSql(beanName) { Sql sql ->\n            def queryResult = sql.firstRow('select count(*) from my_table')\t  \n            queryResult[0]\n        }\n    }\n}\n
\n

Notice that the caller is not responsible for closing the Sql instance that is passed to the closure. The value returned\nby the closure is also the return value of doWithSql.

\n

Credits

\n

The core of this plugin is based on this stackoverflow answer posted by\nTim Yates.

\n" }, { "bintrayPackage": { "name": "dropwizard-metrics", "repo": "plugins", "owner": "grails", "desc": "Monitoring And Metrics Plugin For Grails 3", "labels": [ "metrics", "dropwizard" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails-plugins/grails-dropwizard-metrics/issues", "latestVersion": "2.0.0.RC1", "updated": "2020-03-18T16:05:41.578Z", "systemIds": [ "org.grails.plugins:dropwizard-metrics" ], "vcsUrl": "https://github.com/grails-plugins/grails-dropwizard-metrics" }, "documentationUrl": "https://grails-plugins.github.io/grails-dropwizard-metrics/", "mavenMetadataUrl": null, "readme": "

Grails Dropwizard Metrics

\n

Documentation is available here.

\n" }, { "bintrayPackage": { "name": "dropwizard-metrics-graphite", "repo": "plugins", "owner": "grails", "desc": "Adds Dropwizard metrics reporting to Graphite For Grails 3", "labels": [ "metrics", "dropwizard", "graphite" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails-plugins/grails-dropwizard-metrics-graphite/issues", "latestVersion": "2.0.0.RC1", "updated": "2020-03-18T16:18:55.912Z", "systemIds": [ "org.grails.plugins:dropwizard-metrics-graphite" ], "vcsUrl": "https://github.com/grails-plugins/grails-dropwizard-metrics-graphite" }, "documentationUrl": "https://grails-plugins.github.io/grails-dropwizard-metrics-graphite/", "mavenMetadataUrl": null, "readme": "

Grails Dropwizard Metrics

\n

Documentation is available here.

\n

Grails Dropwizard Metrics - Graphite

\n

Documentation is available here.

\n" }, { "bintrayPackage": { "name": "dynamic-logs-with-rabbit", "repo": "plugins", "owner": "dbpatel219", "desc": "Change Application Log Levels via Rabbit MQ messages at Runtime.", "labels": [ "logging" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/dbpatel219/dynamic-logs-with-rabbit/issues", "latestVersion": "1.0.2", "updated": "2019-10-02T12:05:42.973Z", "systemIds": [ "org.grails.plugins:dynamic-logs-with-rabbit" ], "vcsUrl": "https://github.com/dbpatel219/dynamic-logs-with-rabbit" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

dynamic-logs-with-rabbit

\n

Change Application Log Levels via Rabbit MQ messages at Runtime.

\n\n

Installation

\n

Upon install, this will create a new Rabbit Exchange for you called logLevelExchange of type fanout

\n

Usage

\n

Via Controller

\n
    \n
  1. \n

    Make sure you have a mapping in UrlMappings to logLevel/$action and any security permissions

    \n
  2. \n
  3. \n

    A controller LogLevelController and view are provided to change the log levels from. Simply go to http[s]://yourapp.com/logLevel

    \n
  4. \n
  5. \n

    Simply fill in the form and submit. App Name is the application you would like to change the log level for. LogLevelConsumer matches Grails application.properties "app.name" against the one that is passed in from the form.

    \n
  6. \n
\n

NOTE: Highly recommend you lock down logLevel endpoint via Spring Security.

\n

Via Service

\n
    \n
  1. Inject logLevelService into your services or controllers :
  2. \n
  3. Create a DynamicLogLevelMsg
  4. \n
\n\n

Example

\n
class Foo {\n    def logLevelService\n\n    def changeAllServiceLogLevelsToInfo() {\n        logLevelService.send new DynamicLogLevelMsg("myApp", "grails.app.services", "INFO")\n    }\n}\n
\n

Contributors

\n

Thanks to Burt Beckwith for his contributions & feedback.

\n" }, { "bintrayPackage": { "name": "elasticsearch", "repo": "plugins", "owner": "grails", "desc": "Elasticsearch is a search server based on Lucene. It provides a distributed, multitenant-capable full-text search engine with an HTTP web interface and schema-free JSON documents. Elasticsearch is developed in Java and is released as open source under the terms of the Apache License. This is the Grails 3 plugin to support Elasticsearch", "labels": [ "search", "elasticsearch" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails/elasticsearch-grails-plugin/issues", "latestVersion": "3.0.1", "updated": "2023-06-21T10:07:13.000Z", "systemIds": [ "org.grails.plugins:elasticsearch" ], "vcsUrl": "https://github.com/grails/elasticsearch-grails-plugin" }, "documentationUrl": "https://grails.github.io/elasticsearch-grails-plugin/", "mavenMetadataUrl": "https://repo1.maven.org/maven2/org/grails/plugins/elasticsearch/maven-metadata.xml", "readme": null }, { "bintrayPackage": { "name": "embedded-mongodb", "repo": "plugins", "owner": "grails", "desc": "Executes an embedded mongo database for integration or functional testing", "labels": [ "testing", "database", "mongodb" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails-plugins/grails-embedded-mongodb/issues", "latestVersion": "2.0.1", "updated": "2022-10-17T08:53:50.000Z", "systemIds": [ "org.grails.plugins:embedded-mongodb" ], "vcsUrl": "https://github.com/grails/grails-embedded-mongodb" }, "documentationUrl": "https://grails.github.io/grails-embedded-mongodb/", "mavenMetadataUrl": "https://repo1.maven.org/maven2/org/grails/plugins/embedded-mongodb/maven-metadata.xml", "readme": null }, { "bintrayPackage": { "name": "embedded-mysql", "repo": "plugins", "owner": "purpleraven", "desc": "Plugin allows to use embedded MySQL in application.", "labels": [ "testing", "database", "mysql" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/purpleraven/embedded-mysql-grails-plugin/issues", "latestVersion": "1.1", "updated": "2019-05-15T09:24:00.089Z", "systemIds": [ "org.grails.plugins:embedded-mysql" ], "vcsUrl": "https://github.com/purpleraven/embedded-mysql-grails-plugin" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

embedded-mysql-grails-plugin

\n

\"Download\"

\n

Plugin replaces default embedded H2 datasource in awesome Grails framework\nto MySQL. Plugin uses already existing solution wix-embedded-mysql.

\n

The plugin based on embedded-postgres-grails-plugin

\n

This plugin is not for production use, the main idea to have\nyour development and u-test environment similar to the standalone production MySQl (of course, if you use this DB in the project).

\n

Getting Started

\n

To get started with the minimum of configuration start from the following:\nAdd to your build.gradle

\n
repositories {\n  ...\n  maven { url "http://dl.bintray.com/purpleraven/plugins" }\n  ...\n}\n\nwar {\n    rootSpec.exclude("**/wix-embedded-mysql*.jar")\n}\n\ncompile 'org.grails.plugins:embedded-mysql:1.1'\n
\n

In your application.yml change the dataSource settings to the next one:

\n
dataSource:\n    embeddedMysql: true\n
\n

Prerequisites

\n

Plugin configured to work with Grails 3.0.0 or higher, but theoretically can be used even for\nolder version of it. But this was not checked properly, so contributing is welcome.

\n

Configuration

\n

Plugin uses next parameters in DataSource section:

\n

|Parameter name|Description|Default value|\n|--------------|-----------|-------------|\n| embeddedMysql | Enabling of the plugin, main switcher. | false |\n| embeddedPort | You can define the particular port, which will be used by MySQL instance | random free port |\n| url | You can specify the url with any additional parameters, which MySQL understands | jdbc:mysql://localhost:/embedded_db |\n| username || embedded_db |\n| password || embedded_db |\n| schema || embedded_db |

\n

All other parameters common for the Grails Datasource configuration section are being used by grails dataSource plugin.\nFor example, you can set

\n
dataSource:\n    pooled: true\n    embeddedMysql: true\n
\n

In this case embedded MySQL will be created with connection pool in front of it.

\n

License

\n

Apache License, Version 2.0

\n

Acknowledgments

\n\n

Known problems

\n

apt install libaio1\n'Stream closed': apt install libncurses5

\n" }, { "bintrayPackage": { "name": "embedded-postgres", "repo": "plugins", "owner": "relaximus", "desc": "Plugin allows to use embedded postgres in application.", "labels": [ "testing", "database", "postgres" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/Relaximus/embedded-postgres-grails-plugin/issues", "latestVersion": "1.1.2", "updated": "2019-01-17T15:53:30.576Z", "systemIds": [ "org.grails.plugins:embedded-postgres", "embedded.postgres:embedded-postgres", "embedded.postgres:embedded-postgres-grails-plugin" ], "vcsUrl": "https://github.com/Relaximus/embedded-postgres-grails-plugin" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

embedded-postgres-grails-plugin

\n

\"Build\n\"Download\"

\n

Plugin replaces default embedded H2 datasource in awesome Grails framework\nto Postgres. Plugin uses already existing solution otj-pg-embedded.

\n

This plugin is not for production use, the main idea to have\nyour development and u-test environment similar to the standalone production Postgres (of course, if you use this DB in the project).

\n

Getting Started

\n

To get started with the minimum of configuration start from the following:\nAdd to your build.gradle

\n
repositories {\n    maven {\n        url  "https://dl.bintray.com/grails/plugins" \n    }\n}\n
\n
compile 'org.grails.plugins:embedded-postgres:1.1.2'\n
\n

In your application.yml change the dataSource settings to the next one:

\n
dataSource:\n    embeddedPostgres: true\n
\n

Prerequisites

\n

Plugin configured to work with Grails 3.0.0 or higher, but theoretically can be used even for\nolder version of it. But this was not checked properly, so contributing is welcome.

\n

Configuration

\n

Plugin uses next parameters in DataSource section:

\n

|Parameter name|Description|Default value|\n|--------------|-----------|-------------|\n| embeddedPostgres | Enabling of the plugin, main switcher. | false |\n| embeddedPort | You can define the particular port, which will be used by Postgres instance | random free port |\n| url | You can specify the url with any additional parameters, which Postgres understands | jdbc:postgresql://localhost:/postgres |\n| username || postgres |\n| password || postgres |

\n

All other parameters common for the Grails Datasource configuration section are being used by grails dataSource plugin.\nFor example, you can set

\n
dataSource:\n    pooled: true\n    embeddedPostgres: true\n
\n

In this case embedded Postgres will be created with connection pool in front of it.

\n

License

\n

Apache License, Version 2.0

\n

Acknowledgments

\n\n" }, { "bintrayPackage": { "name": "ember-asset-pipeline", "repo": "asset-pipeline", "owner": "bertramlabs", "desc": "Compiles .hbs or .handlebars files for the asset-pipeline into the Ember TEMPLATES cache", "labels": [ "asset-pipeline", "ember" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/bertramdev/asset-pipeline/issues", "latestVersion": "5.0.1", "updated": "2024-09-13T18:26:39.000Z", "systemIds": [ "com.bertramlabs.plugins:ember-asset-pipeline" ], "vcsUrl": "https://github.com/bertramdev/asset-pipeline" }, "documentationUrl": null, "mavenMetadataUrl": "https://repo1.maven.org/maven2/com/bertramlabs/plugins/ember-asset-pipeline/maven-metadata.xml", "readme": "

Ember Asset-Pipeline

\n

\"Build

\n

MOVED: This project has moved to a sub project of the main asset-pipeline repository http://github.com/bertramdev/asset-pipeline

\n

Overview

\n

The JVM ember-asset-pipeline is a plugin that provides handlebars template precompiler support for Ember.js to asset-pipeline.

\n

Current Ember Version: 1.7.0

\n

For more information on how to use asset-pipeline, visit here.

\n

Usage

\n

Simply create files in your standard assets/javascripts folder with extension .handlebars or .hbs.\nBy default the templateRoot for your template names is specified as 'templates'. This means that any handlebars file within the root assets/javascripts folder will utilize its file name (without the extension) as its template name. Or a file in templates/show.handlebars would be named templates/show. If templates is set as the templateRoot than it would be named show

\n

It is also possible to change the template path seperator for templatenames to be used by handlebars:

\n

Gradle Example:

\n
assets {\n\tconfig = [\n\thandlebars: [\n\t\ttemplateRoot: 'templates',\n\t\ttemplatePathSeperator: '/'\n\t]\n\t]\n}\n
\n

Grails Example:

\n
grails {\n\tassets {\n\t\thandlebars {\n\t\t\ttemplateRoot = 'templates'\n\t\t\ttemplatePathSeperator = "/"\n\t\t}\n\t}\n}\n
\n

To use the handlebars runtime simply add handlebars js to your application.js or your gsp file

\n
//=require handlebars\n
\n

Using in the Browser

\n

Template functions are stored in the Handlebars.templates object using the template name. If the template name is\nperson/show, then the template function can be accessed from Handlebars.templates['person/show']. See the Template Names section for how template names are calculated.

\n

See the Handlebars.js website for more information on using Handlebars template functions.

\n" }, { "bintrayPackage": { "name": "events", "repo": "plugins", "owner": "grails", "desc": "Grails Events - EventBus abstraction for Grails", "labels": [ "async", "events" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails/grails-async/issues", "latestVersion": "5.0.2", "updated": "2024-01-09T11:43:24.000Z", "systemIds": [ "org.grails.plugins:events" ], "vcsUrl": "https://github.com/grails/grails-async" }, "documentationUrl": "https://async.grails.org/latest/guide/index.html#events", "mavenMetadataUrl": "https://repo1.maven.org/maven2/org/grails/plugins/events/maven-metadata.xml", "readme": "" }, { "bintrayPackage": { "name": "exa-datatables", "repo": "plugins", "owner": "exanpe", "desc": "Provides easy integration with DataTables.net (Table plug-in for jQuery)", "labels": [ "datatables.net" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/exanpe/exa-grails-plugins/issues", "latestVersion": "2.0.1", "updated": "2016-12-14T22:46:58.114Z", "systemIds": [ "fr.exanpe.grails:exa-datatables" ], "vcsUrl": "https://github.com/exanpe/exa-grails-plugins" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

exa-grails-plugins

\n

EXA-DATATABLES

\n

This plugin is pre-configured to ease integration with DataTables (Table plug-in for jQuery).\nMost of the important features are enabled by default like:

\n\n

Link to documentation and description

\n

Link to the live Demo

\n

EXA-SECURITY

\n

This plugin provides features to enhance Grails 2.4.x security, as well as few other useful stuff.

\n\n

Link to documentation and description

\n

Link to the live Demo

\n" }, { "bintrayPackage": { "name": "excel-export", "repo": "plugins", "owner": "touk", "desc": "This plugin helps you export data in Excel (xlsx) format, using Apache POI.", "labels": [ "excel", "export" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/TouK/excel-export/issues", "latestVersion": "2.1", "updated": "2017-05-30T21:24:04.936Z", "systemIds": [ "org.grails.plugins:excel-export", "pl.touk:excel-export" ], "vcsUrl": "https://github.com/TouK/excel-export" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

This is the excel-export Grails plugin using Apache POI

\n

\"Build \"Download\"

\n

What does it do?

\n

This plugin allows for easy exporting of object lists to an Office Open XML workbook (Microsoft Excel 2007+ xlsx) file, while still allowing you to handle the export file on a cell-by-cell basis.

\n

An alternative to this plugin is James Kleeh's groovy-excel-builder which provides a fantastic Groovy DSL with varying degress of fine-grained control.

\n

When should I use it?

\n

There are two scenarios for which this plugin was created:

\n
    \n
  1. \n

    When you want to export data from your controllers for download and want to maintain full control of how you handle this data.

    \n
  2. \n
  3. \n

    When your customer says: 'I want 100 reports in this new project' and nobody has any clue what those reports look like, you can use this plugin as a DSL, i.e. tell your client 'Hey, I've got good news. We have a nice DSL for you, so that you can write all those reports yourself. And it's free!' (or charge them anyway).

    \n
  4. \n
\n

In either case, you can export to either a file on disk or to the HTTP response output stream (download as xlsx).

\n

This plugin has been used like this in commercial projects.

\n

How do I use it?

\n

Say, in your controller you have a list of objects, like so:

\n
List<Product> products = productFactory.createProducts()\n
\n

To export selected properties of those products to a file on disk, see the following example, where withProperties is a list of properties that are going to be exported to xlsx, in the given order:

\n
def withProperties = ['name', 'description', 'validTill', 'productNumber', 'price.value']\nnew XlsxExporter('/tmp/myReportFile.xlsx').\n    add(products, withProperties).\n    save()\n
\n

Notice that you can use nested properties (e.g. price.value) of your objects.

\n

To add a header row to the spreadshet and make the file downloadable from a controller, you do this:

\n
def headers = ['Name', 'Description', 'Valid Till', 'Product Number', 'Price']\ndef withProperties = ['name', 'description', 'validTill', 'productNumber', 'price.value']\n\nnew WebXlsxExporter().with {\n    setResponseHeaders(response)\n    fillHeader(headers)\n    add(products, withProperties)\n    save(response.outputStream)\n}\n
\n

WebXlsxExporter is the same thing as XlsxExporter, just with the ability to handle HTTP response headers.

\n

You can also manipulate the file on a cell-by-cell basis:

\n
new WebXlsxExporter().with {\n    setResponseHeaders(response)\n    fillRow(["aaa", "bbb", 13, new Date()], 1)\n    fillRow(["ccc", "ddd", 87, new Date()], 2)\n    putCellValue(3, 3, "Now I'm here")\n    save(response.outputStream)\n}\n
\n

You can also mix approaches (cell-by-cell, and object list):

\n
def withProperties = ['name', 'description', 'validTill', 'productNumber', 'price.value']\n\nnew WebXlsxExporter().with {\n     setResponseHeaders(response)\n     fillRow(["aaa", "bbb", 13, new Date()], 1)\n     fillRow(["ccc", "ddd", 87, new Date()], 2)\n     putCellValue(3, 3, "Now I'm here")\n     add(products, withProperties, 4) //NOTICE: we are adding objects starting from line 4\n     save(response.outputStream)\n}\n
\n

What about multiple sheets?

\n

If you'd like to work with multiple sheets, just call sheet(sheetName) on your exporter. It returns an instance\nof AdditionalSheet that shares the same row/cell manipulation API as the exporter itself:

\n
    List<Product> products = productFactory.createProducts()\n    def withProperties = ['name', 'description', 'validTill', 'productNumber', 'price.value']\n\n    new WebXlsxExporter().with {\n        setResponseHeaders(response)                                                                                                                     print methods of controller\n        sheet('second sheet').with {\n            fillHeader(withProperties)\n            add( products, withProperties )\n        }\n        save(response.outputStream)\n    }\n
\n

You can also mix using additional sheets with a default sheet:

\n
    List<Product> products = productFactory.createProducts()\n    def withProperties = ['name', 'description', 'validTill', 'productNumber', 'price.value']\n\n    new WebXlsxExporter().with {\n        setResponseHeaders(response)\n        fillHeader(withProperties)\n        add( products, withProperties )\n        sheet('second sheet').with {\n            fillHeader(withProperties)\n            add( products, withProperties )\n        }\n        save(response.outputStream)\n    }\n
\n

And if you'd like to change the name of default sheet, just set it before first call:

\n
    WebXlsxExporter webXlsxExporter = new WebXlsxExporter()\n    webXlsxExporter.setWorksheetName("products")\n    webXlsxExporter.with {\n        ...\n    }\n
\n

How to export my own types?

\n

This plugin handles basic property types pretty well (String, Date, Boolean, Timestamp, NullObject, Long, Integer, BigDecimal, BigInteger, Byte, Double, Float, Short). It also handles nested properties, and if everything fails, tries to call toString(). But sooner or later, you'll want to export a property of a different type the way you like it.\nWhat you need to write, is a Getter. Or, better, a PropertyGetter. It's super easy, here is example of one that takes Currency and turns it into a String:

\n
class CurrencyGetter extends PropertyGetter<Currency, String> { // From Currency, to String\n    CurrencyGetter(String propertyName) {\n        super(propertyName)\n    }\n\n    @Override\n    protected String format(Currency value) {\n        return value.displayName // you can do anything you like in here\n    }\n}\n
\n

The format() method allows you customize the value before the object is saved in an xlsx cell.

\n

And, of course, to use it, just add it into the withProperties list, like this:

\n
def withProperties = ['name', new CurrencyGetter('price.currency'), 'price.value']\n\nnew WebXlsxExporter().with {\n    setResponseHeaders(response)\n    add(products, withProperties)\n    save(response.outputStream)\n}\n
\n

Of course we could have just used currency.displayName in withProperties, but you get the idea.

\n

There are two Getters ready for your convenience.

\n

LongToDatePropertyGetter gets a long and saves it as a date in xlsx, while MessageFromPropertyGetter handles i18n. Speaking of which...

\n

How to i18n?

\n

To get i18n of headers in your controller, just use controller's existing message method:

\n
def headers = [message(code: 'product.name.header'),\n    message(code: 'product.description.header'),\n    message(code: 'product.validTill.header'),\n    message(code: 'product.productNumber.header'),\n    message(code: 'price.value.header')]\n
\n

You can do more though. To i18n values, use MessageFromPropertyGetter:

\n
MessageSource messageSource //injected in the controller automatically by Grails, just declare it\n\ndef export() {\n    List<Product> products = productFactory.createProducts()\n\n    def headers = ['name', 'type', 'value']\n    def withProperties = ['name', new MessageFromPropertyGetter(messageSource, 'type'), 'price.value']\n\n    new WebXlsxExporter().with {\n        setResponseHeaders(response)\n        fillHeader(headers)\n        add(products, withProperties)\n        save(response.outputStream)\n    }\n}\n
\n

This will use grails i18n, based on the value of some property (type in the example above) of your objects.

\n

I want fancy diagrams, colours, and other stuff in my Excel!

\n

Making xlsx files look really great with Apache POI is pretty fun but not very efficient. So we have found out that it's easier to create a template manually (in MS Excel or Open Office), load this template in your code, fill it up with data, and hand it back to the user.

\n

For this scenario, every constructor takes a path to a template file (just a normal xlsx file).

\n

After loading the template, fill the data, and save to the output stream

\n
new WebXlsxExporter('/tmp/myTemplate.xlsx').with {\n    setResponseHeaders(response)\n    add(products, withProperties)\n    save(response.outputStream)\n}\n
\n

If you just want to save the file to disk instead of a stream, use a different constructor:

\n
new XlsxExporter('/tmp/myTemplate.xlsx', '/tmp/myReport.xlsx')\n
\n

If you just open an existing file, and save it, like this:

\n
new XlsxExporter('/tmp/myReport.xlsx').with {\n    add(products, withProperties)\n    save()\n}\n
\n

you are going to overwrite it.

\n

But I don't want no template (for whatever reason)

\n

Ok, so if you don't want to use a temple, but want to format a cell style directly in the code, you can still do that.

\n

You can get the cell style like this:

\n
xlsxReporter.getCellAt(0, 0).getCellStyle().getDataFormatString()\n
\n

Of course there is a corresponding setCellStyle() method, but this is a part of the Apache POI API, and is outside the scope of this plugin.

\n

How to get it installed?

\n

Like any other Grails plugin, just add to the dependencies block of your app's build.gradle file:

\n
dependencies {\n    compile "org.grails.plugins:excel-export:2.1"\n}\n
\n

Excluding xerces may or may not be needed, depending on your setup. If you get

\n
Error executing script RunApp: org/apache/xerces/dom/DeferredElementImpl (Use --stacktrace to see the full trace)\n
\n

you NEED to exclude xercesImpl to use ApachePOI. Don't worry, it won't break anything.

\n

If you have more strange problems with xml and you are using Java 7, exclude xml-apis as well.

\n

To understand why you need to exclude anything, please take a look here: http://stackoverflow.com/questions/11677572/dealing-with-xerces-hell-in-java-maven

\n

If you want a working example, clone this project: https://github.com/TouK/excel-export-samples

\n

Alternative plugins and solutions

\n

As noted above, James Kleeh's groovy-excel-builder provides a wonderful Groovy DSL with varying degress of fine-grained control:

\n
XSSFWorkbook workbook = ExcelBuilder.build {\n    sheet {\n        row {\n            cell("Test 1")\n            cell("Test 2")\n        }\n    }\n}\n\nworkbook.write(outputStream)\n
\n

There are others, but most were too simplistic or too 'automagical' for my needs. Apache POI is pretty simple to use itself (and has fantastic API) but we needed something even simpler for several projects. Also a bit DSL-like so our customers could write reports on their own. After preparing a few getters for our custom objects, this is what we ended up with:

\n
def withProperties = ["id", "name", "inProduction", "workLogCount", "createdAt", "createdAtDate", asDate("firstEventTime"),\n    firstUnacknowledgedTime(), firstUnacknowledged(), firstTakeOwnershipTime(), firstTakeOwnership(),\n    firstReleaseOwnershipTime(), firstReleaseOwnership(), firstClearedTime(), firstCleared(),\n    firstDeferedTime(), firstDefered(), firstUndeferedTime(), firstUndefered(), childConnectedTime(), childConnected(),\n    parentConnectedTime(), parentConnected(), parentDisconnectedTime(), parentDisconnected(),\n    childDisconnectedTime(), childDisconnected(), childOrphanedTime(), childOrphaned(), createdTime(), created(),\n    updatedTime(), updated(), workLogAddedTime(), workLogAdded()]\n\ndef reporter = new XlsxReporter("/tmp/sampleTemplate.xlsx")\n\nreporter.with {\n    fillHeader withProperties\n    add events, withProperties\n    save "/tmp/sampleReport1.xlsx"\n}\n
\n

All the methods in withProperties are static imports generating a new instance of a corresponding PropertyGetter implementation. To our surprise, this worked really well with some clients, who started writing their own reports instead of paying us for doing the boring work.

\n

Hope it helps.

\n

License

\n

Copyright 2012-2014 TouK

\n

Licensed under the Apache License, Version 2.0 (the "License");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at

\n
http://www.apache.org/licenses/LICENSE-2.0\n
\n

Unless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an "AS IS" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.

\n

Changes

\n

2.0.1 upgrade poi to 3.12 (thanks to Sergio Maria Matone) and Grails to 3+ (thanks to mansiarora)

\n

0.2.1 calling toString() on unhandled property types, instead of throwing IllegalArgumentException

\n

0.2.0 working with multiple sheets and renaming default sheet

\n

0.1.10 not exporting release plugin dependency anymore (Issue #14)

\n

0.1.9 upgrade to release plugin 3.0.1 (run 'grails refresh-dependencies' if you have problems in grails 2.3.2)

\n

0.1.8: fix for grails 2.3.1 (groovy changing how Mixins see private methods)

\n

0.1.7: fixed Property Type Validation not accepting subclasses

\n

0.1.6: handling maps in object properties

\n" }, { "bintrayPackage": { "name": "excel-import", "repo": "plugins", "owner": "gpc", "desc": "Grails Excel Import Plugin", "labels": [ "excel", "import" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/gpc/grails-excel-import/issues", "latestVersion": "3.0.2", "updated": "2018-08-15T13:39:59.412Z", "systemIds": [ "org.grails.plugins:excel-import" ], "vcsUrl": "https://github.com/gpc/grails-excel-import" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

\"Build

\n

Excel-Import plugin

\n

Excel-Import plugin uses Apache POI [http://poi.apache.org/] library (v 3.17) to parse Excel files.

\n

It's useful for either bootstrapping data, or when you want to allow your users to enter some data using Excel spreadsheets.

\n

Usage:

\n

The core of the plugin is a utilities class, which contains a number of useful methods for dealing with Excel.

\n

org.grails.plugins.excelimport.ExcelImportUtils

\n

There is also an AbstractExcelImporter, which is a class you can extend - it opens and stores the workbook reference.

\n

Reading Information Contained in Rows:

\n

The plugin is designed to parse data out of spreadsheets into format that can then be used to create objects. For example, if you have data like this:

\n

|B |C |D |\n|:-----------|--------------|--------:|\n|Author |Book |# Sold |\n|Shakespeare |King Lear | 1000 |\n|Shakespeare |Hamlet | 10000 |\n|Tolstoy |War and Peace | 200 |

\n

You can pass in parameters map that contains the name of the sheet, row where to start, and how the different columns map to properties of the object you are planning to populate (i.e. values in column B map to title property).

\n
static Map CONFIG_BOOK_COLUMN_MAP = [\n          sheet:'Sheet1', \n\t\t\t startRow: 2,\n          columnMap:  [\n                  'B':'title',\n                  'C':'author',\n                  'D':'numSold',\n          ]\n    ]\n\nList bookList = ExcelImportUtils.convertColumnMapConfigManyRows(workbook, CONFIG_BOOK_COLUMN_MAP)\n
\n

And you'll get back a list of maps:

\n
assert bookParamsList, [\n  [AuthorName:'Shakespeare', BookName:'King Lear', NumSold:1000],\n  [AuthorName:'Shakespeare', BookName:'Hamlet', NumSold:10000],\n  [AuthorName:'Tolstoy', BookName:'War and Peace', NumSold:200],\n]\n
\n

You can then pass the maps to constructors to create a bunch of objects, i.e.\nbookParamsList:

\n
  bookParamsList.each { Map bookParamMap ->\n    new Book (bookParamMap).save()\n  }\n
\n

Reading Information contained in Individual Cells:

\n
static Map CONFIG_BOOK_CELL_MAP = [ \n sheet:'Sheet2', \n cellMap: [ 'D3':'title',\n    'D4':'author',\n    'D6':'numSold',\n  ]\n] \n\nMap bookParams = ExcelImportUtils.convertFromCellMapToMapWithValues(workbook, CONFIG_BOOK_CELL_MAP )\n
\n

There is also ability to handle type errors, empty cells, evaluate formulas, etc. There is also ability to pass in configuration information, i.e. to specify what to do if a cell is empty (i.e. to provide a default value), to make sure a cell is of expected type, etc.

\n

Also, you can do similar things for individual cells, when that is the format, i.e. C10 maps to key "Author", D12 to "AuthorYearBorn', etc. Between targeting individual cells and columns / rows, that satisfied quite many requirements.

\n

Sample Application:

\n

For a sample of usage, please see a sample application you can download from the Plugins GIT (in the 1.1.x branch) (code below is from Bootstrap.groovy)

\n
import org.grails.plugins.excelimport.ExcelImportUtils\nimport org.grails.plugins.excelimport.*\nimport sample.*\n\nclass BookExcelImporter extends AbstractExcelImporter {\n\n  static Map CONFIG_BOOK_CELL_MAP = [ \n     sheet:'Sheet2', \n     cellMap: [ 'D3':'title',\n        'D4':'author',\n        'D6':'numSold',\n\t  ]\n  ] \n \n  static Map CONFIG_BOOK_COLUMN_MAP = [\n          sheet:'Sheet1', \n\t\t\t startRow: 2,\n          columnMap:  [\n                  'B':'title',\n                  'C':'author',\n                  'D':'numSold',\n          ]\n  ]\n\n  public BookExcelImporter(fileName) {\n    super(fileName)\n  }\n\n  List<Map> getBooks() {\n    List bookList = ExcelImportUtils.convertColumnMapConfigManyRows(workbook, CONFIG_BOOK_COLUMN_MAP)\n  }\n\n\n  Map getOneMoreBookParams() {\n    Map bookParams = ExcelImportUtils.convertFromCellMapToMapWithValues(workbook, CONFIG_BOOK_CELL_MAP )\n  }\n\n}\n
\n
class BootStrap {\n\n    def init = { servletContext ->\n\n        //String fileName = "c:\\\\dev\\\\HEAD\\\\plugins\\\\excel-import\\\\test\\\\projects\\\\sample\\\\test-data\\\\books.xls"\n        String fileName = /.\\test-data\\books.xls/\n         BookExcelImporter importer = new BookExcelImporter(fileName);\n    \n         def booksMapList = importer.getBooks();\n         println booksMapList\n\n    \t booksMapList.each { Map bookParams ->\n    \t    def newBook = new Book(bookParams)\n\t        if (!newBook.save()) {\n\t            println "Book not saved, errors = ${newBook.errors}"\n\t        }\n\t     }\n\n         new Book(importer.getOneMoreBookParams()).save()\n\n\t}\n}\n
\n

Note: Apache POI 3.6 Supports Excel 2007 Files, but I haven't tested those.

\n

Also, while formulas evaluation works for most cases, in some complicated cases it does not (i..e when you have a lookup of a looked up value using some unsupported formulas).

\n

The plugin is licensed under Apache V2.

\n

Release History:

\n\n" }, { "bintrayPackage": { "name": "export", "repo": "plugins", "owner": "gpc", "desc": "Grails export plugin", "labels": [ "export", "csv", "excel", "ods", "pdf", "xml" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/gpc/export/issues", "latestVersion": "2.0.0", "updated": "2016-10-03T14:39:59.214Z", "systemIds": [ "org.grails.plugins:export" ], "vcsUrl": "https://github.com/gpc/export" }, "documentationUrl": "https://gpc.github.io/export/", "mavenMetadataUrl": null, "readme": "

\"Build

\n

Grails Export Plugin

\n

Primary fork of the original export plugin. Sources forked from SVN and maintained here.

\n

The user guide can be found here: Documentation

\n" }, { "bintrayPackage": { "name": "external-config", "repo": "plugins", "owner": "sbglasius", "desc": "Load configs with grails.config.locations like in Grails 2.x", "labels": [ "config" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/sbglasius/external-config/issues", "latestVersion": "4.0.0", "updated": "2023-12-29T10:18:00.000Z", "systemIds": [ "dk.glasius:external-config" ], "vcsUrl": "https://github.com/sbglasius/external-config" }, "documentationUrl": null, "mavenMetadataUrl": "https://repo1.maven.org/maven2/dk/glasius/external-config/maven-metadata.xml", "readme": "

See the README on GitHub

" }, { "bintrayPackage": { "name": "facebook-sdk", "repo": "plugins", "owner": "agorapulse", "desc": "Grails Facebook SDK plugin", "labels": [ "facebook" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/agorapulse/grails-facebook-sdk/issues", "latestVersion": "4.1.2", "updated": "2021-01-18T11:56:45.552Z", "systemIds": [ "org.grails.plugins:facebook-sdk" ], "vcsUrl": "https://github.com/agorapulse/grails-facebook-sdk" }, "documentationUrl": "https://agorapulse.github.io/grails-facebook-sdk/", "mavenMetadataUrl": null, "readme": "

Facebook SDK Grails Plugin

\n

\"Build\n\"Download\"

\n

Introduction

\n

The Facebook Platform is a set of APIs that make your application more social. Read more about integrating Facebook with your web site on the Facebook developer site.

\n

This project contains the open source Grails Facebook SDK Plugin that allows you to integrate the Facebook Platform on a website/app powered by Grails.

\n

This plugin is a port of the official Facebook PHP SDK to Grails 3.0.

\n

It supports the latest OAuth2.0 authentication (required since October 1st 2011).

\n

Grails Facebook SDK Plugin provides the following Grails artefacts:

\n\n

WARNING: Facebook API v3.0 is now used by default.

\n

Installation

\n

Declare the plugin dependency in the build.gradle file, as shown here:

\n
dependencies {\n    ...\n    compile "org.grails.plugins:facebook-sdk:4:0.0"\n    ...\n}\n
\n

Config

\n

Create a Facebook app on Facebook Developers, in order to get your own app ID and app secret.

\n

Add your Facebook app parameters to your grails-app/conf/application.yml:

\n
grails:\n    plugin:\n        facebooksdk:\n            app:\n                id: {APP_ID}\n                permissions: {APP_PERMISSIONS} // Ex. ['email','user_photos']\n                secret: {APP_SECRET}\n
\n

By default, latest Graph API v3.3 will be used.\nYou can override default settings with apiVersion setting:

\n
grails:\n    plugin:\n        facebooksdk:\n            apiVersion: v2.3\n
\n

Since FacebookContext should be instantiated at each request, you must use prototype scope for your Controllers (since Grails 2.3, singleton is the default scope).

\n
grails:\n    controllers:\n        defaultScope: prototype\n
\n

Default jQuery selector is $, if you require another one, you can define it globally in your grails-app/conf/application.groovy:

\n
grails:\n    plugin:\n        facebooksdk:\n            customSelector: jQuery\n
\n

Bugs

\n

To report any bug, please use the project Issues section on GitHub.

\n

Feedback

\n

The Grails Facebook SDK is not an official Facebook SDK such as Javascript, PHP, iOS and Android SDKs.

\n

It is developed by AgoraPulse.

\n

The Grails Facebook SDK is licensed under the Apache Licence, Version 2.0.

\n

Breaking Changes

\n

4.0.1

\n\n

4.0.0

\n\n" }, { "bintrayPackage": { "name": "fields", "repo": "plugins", "owner": "grails", "desc": "Grails fields plugin", "labels": [ "forms" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/gpc/fields/issues", "latestVersion": "5.0.3", "updated": "2024-04-08T19:47:32.000Z", "systemIds": [ "io.github.gpc:fields" ], "vcsUrl": "https://github.com/gpc/fields" }, "documentationUrl": "https://gpc.github.io/fields/", "mavenMetadataUrl": "https://repo1.maven.org/maven2/io/github/gpc/fields/maven-metadata.xml", "readme": "Find the latest documentation here: https://gpc.github.io/fields" }, { "displayName": "file-viewer", "comment": "There does not seem to exist a published release version compatible with Grails >= 3 as of this writing.", "bintrayPackage": { "name": "File-Viewer-Grails-Plugin", "repo": "plugins", "owner": "tothenew", "desc": "Grails plugin which allows you to view files stored on the file system.", "labels": [ "file-viewer" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/intelligrape/File-Viewer-Grails-Plugin/issues", "latestVersion": null, "updated": "2016-03-31T13:31:54.746Z", "systemIds": [ "org.grails.plugins:file-viewer" ], "vcsUrl": "https://github.com/tothenew/File-Viewer-Grails-Plugin" }, "documentationUrl": "https://github.com/tothenew/File-Viewer-Grails-Plugin/wiki", "mavenMetadataUrl": null, "readme": null }, { "bintrayPackage": { "name": "filterpane", "repo": "grails-plugins", "owner": "ctoestreich", "desc": "", "labels": [ "filter", "filterpane" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/Grails-Plugin-Consortium/grails-filterpane/issues", "latestVersion": "3.0.9", "updated": "2018-05-04T00:32:57.027Z", "systemIds": [ "org.grails.plugins:filterpane", "org.grails.plugins:grails-filterpane" ], "vcsUrl": "https://github.com/Grails-Plugin-Consortium/grails-filterpane" }, "documentationUrl": "https://Grails-Plugin-Consortium.github.io/grails-filterpane/", "mavenMetadataUrl": null, "readme": "

Filterpane Plugin

\n

####Build Status####

\n

\"Build

\n

####Documentation Found Here####

\n

Documentation

\n

###Demo Project###

\n

Demo

\n" }, { "displayName": "fixtures", "bintrayPackage": { "name": "fixtures3", "repo": "plugins", "owner": "purpleraven", "desc": "Load complex domain data via a simple DSL", "labels": [ ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/purple-raven/fixtures/issues", "latestVersion": "3.0.5", "updated": "2019-02-20T07:38:03.728Z", "systemIds": [ "org.grails.plugins:fixtures3" ], "vcsUrl": "https://github.com/purple-raven/fixtures" }, "documentationUrl": "https://purple-raven.github.io/fixtures/", "mavenMetadataUrl": null, "readme": "

\"Build

\n

\"Download\"

\n

Grails Fixtures Plugin for Grails 3

\n

Documentation can be found @ http://web.archive.org/web/20150527051907/http://gpc.github.io/grails-fixtures

\n
repositories {\n  maven { url "http://dl.bintray.com/purpleraven/plugins" }\n}\n\ndependencies {\n  compile 'org.grails.plugins:fixtures3:3.0.5'\n}\n
\n" }, { "bintrayPackage": { "name": "force-ssl", "repo": "grails3-plugins", "owner": "bertramlabs", "desc": "Creates a simple annotation to mark controller/actions as SSL restricted and performs the appropriate redirect.", "labels": [ "ssl", "https" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/bertramdev/grails-force-ssl/issues", "latestVersion": "5.0.2", "updated": "2024-10-10T14:04:45.000Z", "systemIds": [ "com.bertramlabs.plugins:grails-force-ssl", "com.bertramlabs.plugins:force-ssl" ], "vcsUrl": "https://github.com/bertramdev/grails-force-ssl" }, "documentationUrl": null, "mavenMetadataUrl": "https://repo1.maven.org/maven2/com/bertramlabs/plugins/grails-force-ssl/maven-metadata.xml", "readme": "

Grails Force SSL

\n

The Grails Force SSL Plugin provides an annotation for controllers to force ssl url endpoints. For example, you may want to restrict a shopping cart page or login page to SSL.

\n

Configuration

\n

By default, the SSL plugin is enabled for all environments, with the exception of Development. This can be overridden by adjusting your Config.groovy

\n
grails.plugin.forceSSL.enabled = false\n
\n

Grails 3

\n
grails:\n    plugin:\n        forceSSL:\n            enabled: true\n
\n

The enabled flag can also be defined as a closure which will get passed the request attribute. This allows for evaluation on a per requeset level as to wether or not SSL should be enforced. Can be rather useful for disabling forced SSL for certain URL endpoints (for example server endpoints not behind a load balancer).

\n
grails.plugin.forceSSL.enabled = { request ->\n  if(request.serverName == 'app1.bertramlabs.com') {\n    return false\n  }\n  return true\n}\n
\n

It is also possible to override the https port for the redirect if you want to via:

\n
grails.plugin.forceSSL.sslPort = 6443 //optional\n
\n

Usage

\n

Simply import the SSL annotation and apply at the controller level or at the annotation level.

\n
import com.bertramlabs.plugins.SSLRequired\n\n@SSLRequired //Will encrypt entire controller\nclass SessionController {\n  @SSLRequired //Or here for action level\n  def signin() {\n    //Signin Code Here\n  }\n}\n
\n

Another option is to use a configuration mapping to identify which controllers you wish to be restricted to SSL:

\n
  grails {\n    plugin {\n      forceSSL {\n        enabled = true\n        dashboard {\n          index = true\n        }\n        home = true\n      }\n    }       \n  }\n
\n" }, { "bintrayPackage": { "name": "geb", "repo": "plugins", "owner": "grails", "desc": "Geb Functional Testing for Grails framework", "labels": [ "testing", "geb" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails/geb/issues", "latestVersion": "4.0.0", "updated": "2023-12-13T06:17:33.000Z", "systemIds": [ "org.grails.plugins:geb" ], "vcsUrl": "https://github.com/grails/geb" }, "documentationUrl": null, "mavenMetadataUrl": "https://repo1.maven.org/maven2/org/grails/plugins/geb/maven-metadata.xml", "readme": null }, { "bintrayPackage": { "name": "gorm-graphql", "repo": "plugins", "owner": "grails", "desc": "GORM GraphQL - Generates a GraphQL schema based on entities in GORM", "labels": [ "graphql" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails/gorm-graphql/issues", "latestVersion": "2.0.0", "updated": "2020-04-06T19:35:05.149Z", "systemIds": [ "org.grails.plugins:gorm-graphql-plugin", "org.grails.plugins:gorm-graphql" ], "vcsUrl": "https://github.com/grails/gorm-graphql" }, "documentationUrl": "https://grails.github.io/gorm-graphql/latest/guide/index.html", "mavenMetadataUrl": null, "readme": "

Gorm GraphQL

\n

An automatic GraphQL schema generator for GORM

\n

\"Build

\n

Current documentation https://grails.github.io/gorm-graphql/latest/guide/index.html

\n

Dependencies

\n\n" }, { "deprecated": "This entry in the registry is a duplicate of the entry with the name 'gorm-graphql'. This entry should probably be removed from the registry to avoid confusion.", "bintrayPackage": { "name": "gorm-graphql-plugin", "repo": "plugins", "owner": "grails", "desc": "GORM GraphQL - Generates a GraphQL schema based on entities in GORM", "labels": [ "graphql" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails/gorm-graphql/issues", "latestVersion": "2.0.0", "updated": "2020-04-06T19:35:05.149Z", "systemIds": [ "org.grails.plugins:gorm-graphql-plugin" ], "vcsUrl": "https://github.com/grails/gorm-graphql" }, "documentationUrl": "https://grails.github.io/gorm-graphql/", "mavenMetadataUrl": null, "readme": "

Gorm GraphQL

\n

An automatic GraphQL schema generator for GORM

\n

\"Build

\n

Current documentation https://grails.github.io/gorm-graphql/latest/guide/index.html

\n

Dependencies

\n\n" }, { "displayName": "logical-delete", "bintrayPackage": { "name": "gorm-logical-delete", "repo": "plugins", "owner": "grails", "desc": "Adds logical delete capabilities to GORM", "labels": [ "database", "logical-delete" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails-plugins/gorm-logical-delete/issues", "latestVersion": "2.0.0.M2", "updated": "2017-12-23T16:32:31.613Z", "systemIds": [ "org.grails.plugins:gorm-logical-delete" ], "vcsUrl": "https://github.com/grails-plugins/gorm-logical-delete" }, "documentationUrl": "https://grails-plugins.github.io/gorm-logical-delete/", "mavenMetadataUrl": null, "readme": "

Docs

\n

See grails-plugins.github.io/gorm-logical-delete/.

\n" }, { "bintrayPackage": { "name": "gorm-tools", "repo": "grails-plugins", "owner": "9ci", "desc": "repository pattern, data services, fast data binding and json/rest/map based query plugin for grails gorm", "labels": [ "database" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/yakworks/gorm-tools/issues", "latestVersion": "7.3.77", "updated": "2024-10-17T19:53:23.000Z", "systemIds": [ "org.yakworks:gorm-tools", "org.grails.plugins:gorm-tools" ], "vcsUrl": "https://github.com/yakworks/gorm-tools" }, "documentationUrl": "https://yakworks.github.io/gorm-tools/", "mavenMetadataUrl": "https://repo1.maven.org/maven2/org/yakworks/gorm-tools/maven-metadata.xml", "readme": "

\"CircleCI\"\n\"9ci\"\n\n\n

\n
\n\n      ________                                           _.-````'-,_\n     /  _____/  ___________  _____                   ,-'`           `'-.,_\n    /   \\  ___ /  _ \\_  __ \\/     \\          /)     (\\       9ci's       '``-.\n    \\    \\_\\  (  <_> )  | \\/  Y Y  \\        ( ( .,-') )    Yak Works         ```\n     \\______  /\\____/|__|  |__|_|  /         \\ '   (_/                         !!\n            \\/                   \\/           |       /)           '           !!!\n  ___________           .__                   ^\\    ~'            '     !    !!!!\n  \\__    ___/___   ____ |  |   ______           !      _/! , !   !  ! !  !   !!!\n    |    | /  _ \\ /  _ \\|  |  /  ___/            \\Y,   |!!!  !  ! !!  !! !!!!!!!\n    |    |(  <_> |  <_> )  |__\\___ \\               `!!! !!!! !!  )!!!!!!!!!!!!!\n    |____| \\____/ \\____/|____/____  >               !!  ! ! \\( \\(  !!!|/!  |/!\n                                  \\/               /_(      /_(/_(    /_(  /_(   \n         Version: 7.0.8-v.10\n         \n
\n

6.1.x is for grails 3.3.x and gorm 6.1.x

\n

7.0.x is for grails 4.x and gorm 7.0.x

\n
\n

DOCS ARE OUT OF DATE AND BEING UPDATED FOR BREAKING CHANGES IN 6.1.12-v.X\nALSO MERGING IN DOCS FOR THE REST-API AND AUDITSTAMP THAT WAS MERGED INTO HERE\nMore breaking changes in 7.0.8-v6. is required on domain entity now or it needs to implement @GormRepoEntity

\n
\n

RELEASE NOTES

\n

| Guide | API |\n|------|--------|\n|Released Docs | Released Api\n|snapshot | snapshot

\n
compile "org.grails.plugins:gorm-tools:6.1.12-v.2"\n
\n

Gorm-tools allows your Grails/Gorm project to start with a design of best practices that they can customize along the way.\nThis brings an opinionated starting point to a Grails/Gorm project but without being locked in.\nDevelopers are free to easily customize, replace and disable these patterns when their opinions differ.

\n

Overview

\n

This is a library of tools to help standardize and simplify the service and Restful controller layer business logic for\ndomains and is the basis for the Gorm Rest API plugin{.new-tab}.

\n

Gorm-Tools is the next iteration on the DAO plugin and has been in use for about 10 years processing millions of transactions per day.

\n

There are 3 primary patterns this library enables as detailed below for Repositories,\nMango ( A mongo/graphql like query way to get gorm entity data with a Map) and\nBatch or Bulk inserting and updating with data binding

\n

Domain Repository Services

\n

jump to reference

\n

A repository is a Domain Driven Design pattern. Used a a place logic to validate, bind, persist and query data that resides\neither in a database or NoSql (via GORM usually of course).\nThe design pattern here is a bit similiar to Spring's Repository pattern\nand Grails GORM's new Data Services pattern.

\n

Goals

\n\n

Fast Data Binder & Batch Insert/Update

\n

We process millions of transactions per day and needed more performant binding performance.

\n

Goals

\n\n

JSON Query and Filtering (Mango Query)

\n

The primary motive here is to create an easy dynamic map based way to query any Gorm Datastore (SQL or NoSQL).\nUsing a simple map that can come from json, yaml, groovy config etc...\nA huge motivating factor being able is to be able to have a powerful and flexible way to query using json from a REST\nbased client without having to use GraphQL (the only other clean alternative)\nThe Repositories and RestApiController come with a query(criteriaMap, closure) method. It allows you to get a paginated\nlist of entities restricted by the properties in the criteriaMap.

\n\n
\n

:memo:\nWhilst selectors have many similarities with MongoDB query documents,\nthese arise more from a similarity of purpose and do not necessarily extend to commonality of function or result.

\n
\n

Example\nfor example, sending a JSON search param that looks like this

\n
{\n  "name": "Bill%",\n  "type": "New",\n  "age": {"$gt": 65}\n}\n
\n

would get converted to the equivalent criteria

\n
criteria.list {\n    ilike "name", "Bill%"\n    eq "type", "New"\n    gt "age", 65\n}\n
\n

Developer Notes

\n

Running docs locally

\n

Docs are built with https://yakworks.github.io/docmark/\nRun ./build.sh dockmark-serve or make dockmark-serve

\n

Publishing Plugin Releases

\n

See Developer Docs for info on our release process

\n

Using latests SNAPSHOT

\n

Configure 9ci repo in build.gradle

\n
repositories {\n  maven { url "http://repo.9ci.com/oss-snapshots" }\n }\n
\n

See version.properties for snapshot version

\n
dependencies {\n compile('org.grails.plugins:gorm-tools:x.y.z-SNAPSHOT') { changing = true } \n}\n
\n" }, { "displayName": "advanced-config", "bintrayPackage": { "name": "grails-advanced-config", "repo": "plugins", "owner": "reid", "desc": "Grails Advanced Config Plugin", "labels": [ "config" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/RealizeIdeas/grails-advanced-config/issues", "latestVersion": "1.0", "updated": "2018-02-23T07:24:40.766Z", "systemIds": [ "net.realizeideas:grails-advanced-config" ], "vcsUrl": "https://github.com/RealizeIdeas/grails-advanced-config.git" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Grail Advanced Config Plugin

\n

A small Gradle plugin built to help with Grails config files.

\n

It takes config files from different locations and composes it into application.yml

\n

\"Config

\n

Setup

\n

Basic setup in build.gradle:

\n
buildscript {\n    repositories {\n        maven { url "https://dl.bintray.com/reid/plugins" }\n    }\n    dependencies {\n        classpath 'net.realizeideas:grails-advanced-config:1.0'\n    }\n}\napply plugin: "net.realizeideas.grails-advanced-config"\n
\n

By default plugin takes all input config files from:

\n\n

You can override this behavior and set required config files manually:

\n
advancedConfig {\n   configFiles = files(\n        'grails-app/conf/config1.yml',\n        'grails-app/conf/config2.yml',\n   ) as List\n}\n
\n

Supported file format

\n

For input files:

\n\n

Output file - application.yml

\n" }, { "displayName": "appinfo", "bintrayPackage": { "name": "grails-appinfo", "repo": "plugins", "owner": "ikalizpet", "desc": "A Grails plugin to provide applicaiton system information for health-check and runtime inspection", "labels": [ "health-check" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/ikaliZpet/grails-appinfo/issues", "latestVersion": "2.2", "updated": "2019-06-25T15:29:24.171Z", "systemIds": [ "org.grails.plugins:grails-appinfo" ], "vcsUrl": "https://github.com/ikaliZpet/grails-appinfo" }, "documentationUrl": "https://binlecode.github.io/grails-appinfo/", "mavenMetadataUrl": null, "readme": "

grails-appinfo

\n

Grails plugin to check and monitor application status with a dashboard UI

\n

\"Build

\n

INTRODUCTION

\n

Grails-appinfo Grails plugin is a set of convenient utilities for application\nsystem details, health-check, configuration and monitoring at runtime.

\n

This Grails plugin builds on top of spring boot actuator API with Grails specific\nenhancements on stock actuator endpoints.

\n

To consume actuator JSON endpoints, the testing Grails application also provides a monitoring\ndashboard inspired by grails-actuator-ui.

\n

The dashboard UI is built on bootstrap with CSS framework from AdminLTE.

\n

This repository contains source code of Grails-appinfo plugin, and a testing host Grails application.

\n

INSTALL

\n

In host Grails application's build.gradle file:

\n
plugins {\n    compile ':grails-appinfo:$version'\n}\n
\n

PREREQUISITES

\n

Hosting Grails application version 3.0+.

\n

CONFIGURATION

\n

In host Grails application grails-app/conf/application.yml

\n
# Appinfo grails plugin settings\nappinfo:\n    health:\n        mongodb:\n            # hide or show password in the mongodb connection url if it contains credential info\n            # if set to false (default if not set), the password will be replaced as '<pswd>'\n            showPassword: false  # default to false\n        urls:   # list of webservice endpoints to check\n            - url: 'http://localhost:8080'\n              name: 'web root'   # name of the endpoint\n              method: 'GET'      # http method, default to 'HEAD' if not given\n            - url: 'http://localhost:8080/info'\n              name: 'web_info'\n        aws:\n            s3:\n                # either:\n                bucket: 'bucket-name'  # bucket name used in s3 health check\n                # or: (for multiple buckets)\n                #buckets:\n                #    - 'bucket-name'\n                #    - 'another-bucket-name'\n    info:\n        # add 'grails-system-info' to Actuator info endpoint, default (if not set) is not enabled\n        system: true\n        # add 'grails-logging-info' to Actuator info endpoint, default (if not set) is not enabled\n        logging: true\n        # add following keys to Actuator info endpoint, default (if not set) is not enabled\n        # - 'jvm-version'\n        # - 'groovy-version'\n        # - 'grails-runtime-environment'\n        # - 'grails-reload-enabled'\n        # - 'grails-runtime-threads-info'\n        runtime: true\n
\n

SAMPLE APPLICATION

\n

The plugin provides RESTful json view by itself with endpoints as below:\n<root-context>/ followed by autoconfig, configprops, dump, env, health, info, metrics, mappings, shutdown, trace, beans.

\n

Most of them are decorators of Spring Boot Actuator native endpoints. But with enhanced information and connectivity support such as mongodb, s3, generic web url endpoint, etc.

\n

For example, localhost:8080/health endpoint returns:

\n
{\n    "status": "DOWN",\n    "diskSpace": {\n        "status": "UP",\n        "total": 499963170816,\n        "free": 281595985920,\n        "threshold": 262144000\n    },\n    "urlHealthCheck_web_info": {\n        "status": "UP",\n        "url": "http://localhost:8080/info",\n        "method": "HEAD",\n        "timeout.threshold": "10000 ms"\n    },\n    "databaseHealthCheck": {\n        "status": "UP",\n        "database": "H2",\n        "hello": 1\n    },\n    "urlHealthCheck_webroot": {\n        "status": "UP",\n        "url": "http://localhost:8080",\n        "method": "GET",\n        "timeout.threshold": "10000 ms"\n    },\n    "mongodbHealthCheck": {\n        "status": "DOWN",\n        "url": "mongodb://localhost/test_grails_appinfo",\n        "db": "test_grails_appinfo",\n        "error": "java.lang.Exception: MongoDB check timed out after 3000 ms"\n    },\n    "s3HealthCheck": {\n        "status": "DOWN",\n        "endpoint": "https://s3.amazonaws.com",\n        "error": "java.lang.Exception: S3 check fail: Unable to load AWS credentials from any provider in the chain"\n    }\n}\n
\n

The sample application also includes a Bootstrap styled dashboard with url:\n<root-context>/appinfoDashboard which renders information with ajax call to above endpoints.

\n

The web UI components are straightforward:

\n\n

UI static resource files are:

\n\n

Here are some screenshots of v1.3 sample application UI:

\n\n

CHANGELOG

\n

1.3.1

\n\n

1.3

\n\n

1.2

\n\n

v1.1

\n\n

v1.0

\n\n

v0.9

\n\n

CONTRIBUTORS

\n

Bin Le (bin.le.code@gmail.com)

\n

LICENSE

\n

Apache License Version 2.0. (http://www.apache.org/licenses/)

\n" }, { "displayName": "bootstrap-forms", "bintrayPackage": { "name": "grails-bootstrap-forms", "repo": "plugins", "owner": "jvilaplana", "desc": "Easy form fields generation taglib.", "labels": [ "bootstrap" ], "licenses": [ "MIT" ], "issueTrackerUrl": "https://github.com/jvilaplana/grails-bootstrap-forms/issues", "latestVersion": "0.3.3", "updated": "2020-08-19T09:16:59.593Z", "systemIds": [ "grails.bootstrap.forms:grails-bootstrap-forms" ], "vcsUrl": "https://github.com/jvilaplana/grails-bootstrap-forms" }, "documentationUrl": "https://jvilaplana.github.io/grails-bootstrap-forms/", "mavenMetadataUrl": null, "readme": "

Grails Bootstrap Forms

\n

A Grails 3 plugin to automatically generate form fields using Bootstrap 4.

\n

Overview

\n

The grails-bootstrap-forms plugin offers an easy-to-use TagLib to render fields in views.

\n

Basic usage

\n

Add the Bintray repository to your build.gradle file:

\n
buildscript {\n    repositories {\n        ...\n        maven { url "http://dl.bintray.com/jvilaplana/plugins" }\n    }\n}\n
\n

Add the dependency to your project's build.gradle file:

\n
dependencies {\n    ...\n    compile 'grails.bootstrap.forms:grails-bootstrap-forms:0.3.3'\n}\n
\n

Add the stylesheet to your project's application.css file:

\n
*= require bootstrap-forms\n
\n

There is a tag to display a field for show.gsp views and another one to render form fields.

\n

To show a field you can use:

\n

<bf:showField bean="${user}" property="username" />

\n

To render a form field you can use:

\n

<bf:formField bean="${user}" property="username" />

\n

Documentation

\n

showField attributes

\n

| Attribute | Description |\n| --------- | ----------- |\n| bean | Instance |\n| property | Property of the bean to be rendered |\n| width | Column width, defaults to 3 |\n| type | Type of the property to be rendered. One of text, textarea, number, date, time, datetime or select. If not specified, the type will be guessed.\n| addon | If specified, its value will be appended to the field. |\n| cssClass | A CSS class that will be added to the field |

\n

formField attributes

\n

| Attribute | Description |\n| --------- | ----------- |\n| bean | Instance |\n| property | Property of the bean to be rendered |\n| width | Column width, defaults to 3 |\n| type | Type of the property to be rendered. One of text, textarea, number, date, time, transient or select. If not specified, the type will be guessed.\n| addon | If specified, its value will be appended to the field. |\n| cssClass | A CSS class that will be added to the field |\n| required | Set its value to required to set the field as required. |\n| height | Set the sizing of the field to lg or sm.\n| rows | Set the number of rows for fields with type="textarea".\n| name | Set the name and id attributes of the field. Defaults to property. |

\n

\"Download\"

\n" }, { "displayName": "executor", "deprecated": "Source repository is archived. As per the readme: This plugin is not maintained - use grails-async. This entry in the registry should probably be removed.", "bintrayPackage": { "name": "grails-executor", "repo": "plugins", "owner": "uberall", "desc": "Full plugin description", "labels": [ "async" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/uberall/grails-executor/issues", "latestVersion": "0.4", "updated": "2016-08-22T06:44:29.831Z", "systemIds": [ "org.grails.plugins:grails-executor" ], "vcsUrl": "https://github.com/uberall/grails-executor" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

grails-executor

\n

DEPRECATION NOTE: this plugin is not maintained anymore, as grails 3.x already has a feature build-in which allows creating a thread that has a session bound. Check out the grails-async documentation for more information: https://async.grails.org/

\n

Concurrency / asynchronous / background process plugin for grails 3

\n

grails2 version can be found here: https://github.com/basejump/grails-executor

\n

Summary

\n

This grails plugin incorporates the java concurrency Executor Framework into a plugin so your grails app can take advantage of asynchronous (background thread / concurrent) processing. The main need for this as opposed to just using an ExecutorService from Executors is that we need to wrap the calls so there is a Hibernate or other Data provider session bound to the thread.\nThis uses the following pattern to wrap Runnable/Closures so they get a session for whatever Gorm you are using. Hibernate being the default but this is also tested with Mongo (no heavily) See the info on the PersistenceContextInterceptor grails bean for more info

\n
// injected spring bean\nPersistenceContextInterceptor persistenceInterceptor\n\nprotected wrap(Closure wrapped) {\n\tpersistenceInterceptor.init()\n\ttry {\n\t\twrapped()\n\t} finally {\n\t\tpersistenceInterceptor.flush()\n\t\tpersistenceInterceptor.destroy()\n\t}\n}\n
\n

Here are a couple of links to get give you some background information.

\n

http://www.ibm.com/developerworks/java/library/j-jtp1126.html
\nhttp://www.vogella.de/articles/JavaConcurrency/article.html

\n

and here are few good write up on groovy concurrency
\nhttp://groovy.codehaus.org/Concurrency+with+Groovy
\nand a slide show
\nhttp://www.slideshare.net/paulk_asert/groovy-and-concurrency-paul-king

\n

Installation

\n

Edit build.gradle, by adding the following:

\n
repositories {\n    ...\n    maven { url "http://dl.bintray.com/uberall/plugins" }\n    ...\n}\n\ndependencies {\n    ...\n    compile 'org.grails.plugins:grails-executor:0.2'\n    ...\n}\n
\n

Setup

\n

The plugin sets up a Grails service bean called executorService so you need do nothing really. It delegates to an implementation of an Java ExecutorService (not to be confused with a Grails Service) interface so read up on that for more info on what you can do with the executorService. It basically wraps another thread pool ExecutorService. By default it uses the java Executors utility class to setup the injected thread pool ExecutorService implementation. The default Grails executorService config looks like this

\n
    executorService(PersistenceContextExecutorWrapper) { bean ->\n        bean.destroyMethod = 'destroy'\n        persistenceInterceptor = ref("persistenceInterceptor")\n        executor = Executors.newCachedThreadPool()\n    }\n
\n

You can override it and inject your own special thread pool executor using Executors by overriding the bean in conf/spring/resources.groovy or the doWithSpring closure in your plugin.

\n
    executorService(PersistenceContextExecutorWrapper) { bean ->\n        bean.destroyMethod = 'destroy'\n        persistenceInterceptor = ref("persistenceInterceptor")\n    // this can be whatever from Executors (don't write your own and pre-optimize)\n    executor = Executors.newCachedThreadPool(new YourSpecialThreadFactory()) \n    }\n
\n

Usage

\n

You can inject the executorService into any bean. It's a PersistenceContextExecutorWrapper that delegates any calls to a concrete ExecutorService implementation.Remember that a Closure is a Runnable so you can pass it to any of the methods that accept a runnable. A great example exists here on the groovy site

\n

The plugin adds shortcut methods to any service/controller/domain artifacts.

\n\n

NOTE ON TRANSACTIONS: keep in mind that this is spinning off a new thread and that any call will be outside of the transaction you are in. Use .withTransaction inside your closure, runnable or callable to make your process run in a transaction that is not calling a transactional service method (such as when using this in a controller).

\n

Examples

\n

in a service/domain/controller just pass a Closure or Runnable to runAsync

\n
class someService {\n\n\tdef myMethod(){\n\t\t..do some stuff\n\t\trunAsync {\n\t\t\t//this will be in its own trasaction \n\t\t\t//since each of these service methods are Transactional\n\t\t\tcalcAging() \n\t\t}\n\t\t.. do some other stuff while aging is calced in background\n\t}\n\n\tdef calcAging(){\n\t\t...do long process\n\t}\n}\n
\n

or inject the executorService

\n
class someService {\n\tdef executorService\n\n\tdef myMethod(){\n\t\t....do stuff\n\t\tdef future = executorService.submit({\n\t\t\treturn calcAging() //you can of course leave out the "return" here\n\t\t} as Callable)\n\t\t.. do some other stuff while its processing\n\t\t//now block and wait with get()\n\t\tdef aging = future.get()\n\t\t..do something\n\t}\n\n\tdef calcAging(){\n\t\t...do long process\n\t\treturn agingCalcObject\n\t}\n\n}\n
\n

or during a domain event

\n
class Book {\n\tdef myNotifyService\n\t\n\tString name\n\t\n\tdef afterInsert(){\n\t\trunAsync {\n\t\t\tmyNotifyService.informLibraryOfCongress(this)\n\t\t}\n\t}\n}\n
\n

the callAsync allows you to spin of a process and calls the underlying executorService submit

\n
class someService {\n\tdef myMethod(){\n\t\t....do stuff\n\t\tdef future = callAsync {\n\t\t\treturn calcAging() //you can of course leave out the "return" here\n\t\t}\n\t\t.. do some other stuff while its processing\n\t\t//now block and wait with get()\n\t\tdef aging = future.get()\n\t\t..do something with the aging\n\t}\n\n\tdef calcAging(){\n\t\t...do stuff\n\t\treturn agingCalcObject\n\t}\n}\n
\n

TODOs

\n\n

Release Notes

\n\n" }, { "bintrayPackage": { "name": "google-visualization", "repo": "plugins", "owner": "bmuschko", "desc": "Grails grails-google-visualization plugin", "labels": [ "google" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/bmuschko/grails-google-visualization/issues", "latestVersion": "2.2.1", "updated": "2016-12-07T08:21:55.677Z", "systemIds": [ "org.grails.plugins:grails-google-visualization" ], "vcsUrl": "https://github.com/bmuschko/grails-google-visualization" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

\"Travis

\n

Grails Google Visualization plugin

\n

Overview

\n

This Grails plugin provides a taglib for the interactive charts of the Google Visualization API.

\n

Documentation

\n

You can find the full documentation in the corresponding GitHub wiki here.

\n

News

\n\n

Features

\n\n" }, { "bintrayPackage": { "name": "gscripting", "repo": "maven", "owner": "frnktrgr", "desc": "Run Groovy scripts in Grails", "labels": [ "scripting" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/frnktrgr/grails-gscripting/issues", "latestVersion": "1.1.0", "updated": "2018-11-09T15:02:48.639Z", "systemIds": [ "org.grails.plugins:gscripting" ], "vcsUrl": "https://github.com/frnktrgr/grails-gscripting" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

grails-gscripting

\n

Run Groovy scripts in Grails

\n

##Logging (Config.groovy):

\n
debug 'grails.plugin.gscripting',\n      'grails.app.services.grails.plugin.gscripting'\n
\n

##Create a script and run it

\n
def gscriptingService\ndef sre = gscriptingService.createScriptRuntimeEnv("Foo", '''\nprocess([c:"hello", d:"world"]) {\n  // call another service\n\t// app.fooService.bar();\n\tlog.info("callParams: "+ctx.callParams);\n\tlog.info("scriptParams: "+scriptParams);\n\tlog.debug("metadata: "+ctx.metadata);  3 + 4 + 2\n}\n''')\nsre.run([a:23, b:42])\nsre.run()\n
\n

gscriptingService.createScriptRuntimeEnv(String label, String sourcecode) creates a new script with the default DSL provider. In the closure given as an argument to process(Map scriptParams) { <HERE> } you can use some DSL properties as described below:

\n\n

##Register script and run by qualified name

\n
def gscriptingService\ngscriptingService.registerScriptRuntimeEnv("foo.Bar", '''\nprocess([first:"hello", second:"world"]) {\n\t// call another service\n\t// app.fooService.bar();\n\tlog.info("callParams: "+ctx.callParams);\n\tlog.info("scriptParams: "+scriptParams);\n\tlog.debug("metadata: "+ctx.metadata);  3 + 4 + 2\n}\n''')\ngscriptingService.run("foo.Bar")\ngscriptingService.run("foo.Bar", [a:23, b:42])\n
\n

In order to provide a script to your whole application, you can register a script under a qualified name. Register an updated script again with the same qualified name in order to reload it.

\n

##Multi-threading and thread-safety\nRunning scripts is thread-safe. If a script is still running and you invoke run again, e.g. in another thread, a new instance will be created and started. The actual instance index can be accessed via the context (see above instanceIndex).

\n" }, { "deprecated": "Source repository is archived. This entry should probably be removed from the registry.", "bintrayPackage": { "name": "hibernate-filter", "repo": "grails-plugins", "owner": "piotrchowaniec", "desc": "", "labels": [ "database" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/fingo/grails-hibernate-filter/issues", "latestVersion": "0.2.0", "updated": "2017-11-07T07:34:55.834Z", "systemIds": [ "org.grails.plugins:grails-hibernate-filter" ], "vcsUrl": "https://github.com/fingo/grails-hibernate-filter" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

grails-hibernate-filter

\n

Description

\n

This is a fork of the original Grails Hibernate Filter Plugin\ncreated from fork appcela/grails-hibernate-plugin\nto make it work with the Grails 3 and Hibernate 4.

\n

This repo contains two projects:

\n
    \n
  1. hibernate-filter-plugin - with plugin code
  2. \n
  3. hibernate-filter-example - with example application using plugin
  4. \n
\n

Usage

\n

Build Plugin File

\n

Clone the repository and execute in main directory command:

\n
./gradlew hibernate-filter-plugin:jar\n
\n

You can publish it to your maven local repository using:

\n
./gradlew hibernate-filter-plugin:publishToMavenLocal\n
\n

Running example application

\n

To run example application use command:

\n
./gradlew hibernate-filter-example:bootRun\n
\n

Use plugin in your application

\n

Add dependency in build.gradle:

\n
compile "org.grails.plugins:grails-hibernate-filter:0.2.0"\n
\n

Configure dataSource in application.yml

\n
configClass: org.grails.plugin.hibernate.filter.HibernateFilterDomainConfiguration\n
\n

Usage

\n

Please refer to the official Grails Hibernate Filter Plugin for usage.

\n

Continuous integration server

\n

\"Build

\n" }, { "bintrayPackage": { "comment": "Does not work with Grails > 3.2.* as of v0.5.5 (according to https://github.com/alexkramer/grails-hibernate-filter/issues/13)", "name": "hibernate-filter", "repo": "grails3-plugins", "owner": "goodstartgenetics", "desc": "Provides utilities to define hibernate filters on classes and collections. Meant to be used with Grails 3.2 and higher, Hibernate 5, and GORM 6", "labels": [ "database" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/alexkramer/grails-hibernate-filter/issues", "latestVersion": "0.5.5", "updated": "2019-05-30T00:38:57.314Z", "systemIds": [ "org.grails.plugins:hibernate-filter-plugin" ], "vcsUrl": "https://github.com/alexkramer/grails-hibernate-filter" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

grails-hibernate-filter

\n

Description

\n

This is a fork of the original Grails Hibernate Filter Plugin\ncreated from fork fingo/grails-hibernate-plugin\nto make it work with Grails 3.2.3 > *, Hibernate 5, and GORM 6.

\n

This repo contains two projects:

\n
    \n
  1. hibernate-filter-plugin - with plugin code
  2. \n
  3. hibernate-filter-example - with example application using plugin
  4. \n
\n

Usage

\n

Build Plugin File

\n

Clone the repository and execute in main directory command:

\n
./gradlew hibernate-filter-plugin:jar\n
\n

You can publish it to your maven local repository using:

\n
./gradlew hibernate-filter-plugin:publishToMavenLocal\n
\n

Running example application

\n

To run example application use command:

\n
./gradlew hibernate-filter-example:bootRun\n
\n

Installation

\n

Add dependency in build.gradle:

\n
repositories {\n    maven { url "https://dl.bintray.com/goodstartgenetics/grails3-plugins/" }\n}\n\ndependencies {\n    compile "org.grails.plugins:hibernate-filter-plugin:0.5.5"\n}\n
\n

Usage

\n

Please refer to this project's wiki for usage.

\n

Continuous integration server

\n

\"Build

\n" }, { "bintrayPackage": { "name": "isomorphic", "repo": "plugins", "owner": "zacharyklein", "desc": "Grails Isomorphic Rendering Plugin", "labels": [ "isomorphic", "ssr", "javascript", "react" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/ZacharyKlein/grails-isomorphic/issues", "latestVersion": "1.2", "updated": "2016-12-02T17:18:40.820Z", "systemIds": [ "org.grails.plugins:grails-isomorphic" ], "vcsUrl": "https://github.com/ZacharyKlein/grails-isomorphic" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

grails-isomorphic

\n

Grails Isomorphic Rendering Plugin

\n

\"Build

\n

This plugin provides a single GSP taglib, <iso:javascript/> which will allow rendering a JavaScript file through Nashorn on the server, as well as loading the same JavaScript on the client. This plugin was designed to be used with React, but is not limited to that library.

\n

Usage

\n

The <iso:javascript /> tag requires two attributes, path and data. path should be a resource path to a JavaScript file. Since for true isomorphic behavior the JavaScript needs to be loaded on the client in addition to the server, /src/main/webapp is an ideal location (however it will not work if you deploy your app as a JAR file). Otherwise, a publicPath attribute is supported to supply an alternate path for the client JavaScript file.

\n

Example:

\n
    <iso:javascript path='bundle.js' data={[some: data]}/> <!-- this will load /src/main/webapp/bundle.js for both server and client (because resources in src/main/webapp are made available by default, e.g., static/bundle.js  -->\n    \n    <iso:javascript path='bundle.js' publicPath='assets/bundle.js' data={[some: data]}/> <!-- this will load /src/main/resources/bundle.js for the server and grails-app/assets/javascripts/bundle.js for the client  -->\n
\n

The data attribute takes a map of data to be converted into a JSON object, which can be parsed and used in your JavaScript to supply initial data.

\n

Example:

\n

<iso:javascript path='bundle.js' data={[a: 1, b: 2]}/>

\n

The actual JavaScript bundle can contain any valid JavaScript code, however it is important to note that Nashorn does not support DOM features, CSS, or other browser-specific APIs. React code using JSX will need to be transpiled via Babel/webpack or some other means in order to be correctly evaluated by Nashorn.

\n

In addition, the plugin expects that the JavaScript bundle will include two top-level "render" functions, one for the browser and one for the server. These functions should take the initial JSON object as a single argument. By default, these functions are expected to be named renderClient and renderServer - you can customize these names via the clientRenderFunction and serverRenderFunction attrs on the iso:javascript tag.

\n

Here is a simple JavaScript bundle that can be evaluated on both the browser and the server, assuming that the data attribute was supplied with [a:1, b:2]:

\n
//bundle.js\n\nif (typeof window !== 'undefined' && typeof document !== 'undefined' && typeof document.createElement === 'function') {\n  window.renderClient = (data) => {\n    return data.a + data.b;  //will return 3.0\n  }\n}\nelse {\n  global.renderServer = (data) => {\n    let json = JSON.parse(data);\n    return json.a + json.b;  //will return 3.0\n  };\n}\n
\n

When writing isomorphic React, it is important to make sure that the client and server-side rendered code is identically, or React will be unable to reuse the server-side rendered code. For this reason, the plugin will always supply both the client and server render functions with the same data - this should evaluate your React code the same way on both platforms.

\n

Please see this sample project to see the plugin usage in conjunction with webpack, using the React profile for Grails.

\n" }, { "bintrayPackage": { "name": "java8", "repo": "plugins", "owner": "grails", "desc": "Provides support for Java 8 specific features in Grails", "labels": [ "java-date-time" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails-plugins/grails-java8/issues", "latestVersion": "1.2.3", "updated": "2020-07-06T19:52:59.484Z", "systemIds": [ "org.grails.plugins:grails-java8" ], "vcsUrl": "https://github.com/grails-plugins/grails-java8" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

grails-java8

\n

\"Build

\n

A plugin to support Java 8 specific functionality

\n" }, { "bintrayPackage": { "comment": "This plugin has been updated to Grails 4 but there is no release yet that works with Grails > 3", "name": "json-apis", "repo": "plugins", "owner": "gregopet", "desc": "", "labels": [ "json" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/gregopet/grails-json-apis/issues", "latestVersion": "0.98", "updated": "2016-03-31T13:31:54.983Z", "systemIds": [ "org.grails.plugins:json-apis" ], "vcsUrl": "https://github.com/gregopet/grails-json-apis.git" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

json-apis

\n

Grails plugin for managing multiple JSON apis using domain class annotations

\n

The goal of this plugin is to help convert Grails domain classes into various\nJSON representations needed in different parts of your web application or to\nsupport various API versions.

\n

Features:

\n\n

Example of use

\n

Several API variants can be easily defined in domain classes by annotating properties with\nJsonApi and providing a list of API profile names under which that property should appear in the\nresulting JSON. Marking a property with the JsonApi annotation but providing no API names will\ninclude that property in all APIs. The database identity property will always be included\nautomatically. One could for instance define the following domain class:

\n
import grails.plugins.jsonapis.JsonApi\n\nclass User {\n\t@JsonApi\n\tString screenName\n\n\t@JsonApi('userSettings')\n\tString email\n\n\t@JsonApi(['userSettings', 'detailedInformation'])\n\tString twitterUsername\n}\n
\n

Then in the controller one would call the desired named JsonApi configuration to get only\nthe fields defined for that API. The following code:

\n
JSON.use("detailedInformation") {\n\trender person as JSON\n}\n
\n

...would convert the person object into JSON containing the id, screenName and twitterUsername\nproperties but not the email. It works for collections as well, converting each collection\nmember using the same API profile that was used to convert the parent:

\n
static hasMany = [\n\tpets: Pet\n]\n@JsonApi('detailedInformation')\nSet pets\n
\n

To include a domain object's parent in a JSON API, declare a belongsTo property explicitly\nand annotate it with JsonApi (but be careful not to create circular paths by including both\nends of a belongsTo/hasMany pair):

\n
static belongsTo = [\n\tuser:User\n]\n\n@JsonApi('petDetails')\nUser user\n
\n

JSONBuilder is supported, too:

\n
JSON.use("userSettings") {\n\trender(contentType: "text/json") {\n\t\tuser = User.first()\n\t\tpet = Pet.first()\n\t}\n}\n
\n

Testing support

\n

To register named marshallers in unit tests, you can use a static method that accepts the marshaller name\nthe classes you need registered:

\n
JsonApiRegistry.registerMarshaller("detailedInformation", ViciousPet)\n
\n

Future plans

\n\n" }, { "bintrayPackage": { "name": "mailgun", "repo": "grails-plugin", "owner": "orkonano", "desc": "Grails grails-mailgun plugin", "labels": [ "mail", "mailgun" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/orkonano/grails-mailgun/issues", "latestVersion": "2.0.3-b", "updated": "2017-05-23T16:48:32.561Z", "systemIds": [ "org.grails.plugins:grails-mailgun" ], "vcsUrl": "https://github.com/orkonano/grails-mailgun" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

\"Build\n\"Project\n\"Stories

\n

grails-mailgun

\n

Grails plugin to use Mailgun Api.

\n

\ufffd\ufffd\ufffd\ufffdIMPORTANT!\nYou need to create your own mailgun account. The plugin doesn't work without a valid api-key and a valid domain

\n

Config parameters

\n

You need to set into your Config.groovy the following properties:

\n
mailgun{\n       apiKey = 'test'\n       domain = 'test'\n\n       message{\n              defaultFrom = 'test'\n              defaultTo = 'test'\n              defaultSubject = 'BigHamlet tiene promociones para vos'\n              format = 'html'\n              defaulTemplate = '/test/mailgunTest'\n              defaultReplyTo = 'test'\n       }\n}\n
\n

The full list of properties is:

\n
mailgun{\n       apiKey = 'test'\n       domain = 'test'\n\n       message{\n              defaultFrom = 'test'\n              defaultTo = 'test'\n              defaultSubject = 'BigHamlet tiene promociones para vos'\n              format = 'html'\n              defaulTemplate = '/test/mailgunTest'\n              defaultReplyTo = 'test'\n       }\n\n       tracking{\n              enabled = 'yes'\n              clicks{\n                     enabled = 'yes'\n              }\n              opens{\n                     enabled = 'yes'\n              }\n       }\n}\n
\n

Mailgun Features

\n

The plugin allows to work with some features of mailgun:

\n\n

Email Html Render

\n

The plugin define a default email html render. DefaultEmailHtmlRender.groovy\nIt render a view (gsp) passing a model as params

\n
\n    String render(Map params){\n        groovyPageRenderer.render view: params.view, model: params.model\n    }\n    \n
\n

Examples

\n
 class TestController {\n\n    def mailgunService\n\n    def index() {\n        RestResponse resp = mailgunService.allLists\n\n        render resp.json.items\n    }\n\n    def send() {\n        RestResponse resp = mailgunService.sendMessage()\n\n        render resp.status\n    }\n}\n
\n

Examples

\n
 class TestController {\n\n    def mailgunService\n\n    def index() {\n        RestResponse resp = mailgunService.allLists\n\n        render resp.json.items\n    }\n\n    def send() {\n        RestResponse resp = mailgunService.sendMessage()\n\n        render resp.status\n    }\n}\n
\n

MailgunService implements all features.

\n

The method allLists, lists all mail lists created in mailgun.

\n

The method sendMessage, sends a new message across mailgun api.

\n" }, { "bintrayPackage": { "name": "mailwatcher", "repo": "plugins", "owner": "junehasissues", "desc": "This Plugin reads unread mails from provided mail account Id. To Grails 3 updated Version of https://github.com/IntelliGrape/Grails-Mail-Watcher-Plugin.", "labels": [ "mail" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/JuNeHasIssues/grails-mailwatcher/issues", "latestVersion": "0.4.1", "updated": "2019-06-27T09:56:24.945Z", "systemIds": [ "org.grails.plugins:mailwatcher" ], "vcsUrl": "https://github.com/JuNeHasIssues/grails-mailwatcher" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

grails-mailwatcher

\n

To Grails 3 updated Version of https://github.com/IntelliGrape/Grails-Mail-Watcher-Plugin

\n

Usage Information

\n

Configure: The plugin needs the following properties

\n
grails {\n    mailwatcher {\n        email = "_youremailId_"\n        password = "_password_"\n        readTimeOut = 10000\n        folderToRead="Inbox"\n        protocol = "imaps"\n        host = "imap.gmail.com"\n        port = "993"\n        excludeSender = "test@test.com,test1@test1.com"\n        filterSubject = "/\\test-pattern.*$/"\n    }\n}\n
\n\n

To log the mails that are read, change the logging level to info

\n
\n

RoadMap

\n\n" }, { "bintrayPackage": { "name": "melody", "repo": "plugins", "owner": "sergiomichels", "desc": "Integrate JavaMelody monitoring into Grails application.", "labels": [ "javamelody" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/javamelody/grails-melody-plugin/issues", "latestVersion": "1.80.0", "updated": "2019-12-12T21:36:08.862Z", "systemIds": [ "org.grails.plugins:grails-melody-plugin" ], "vcsUrl": "https://github.com/javamelody/grails-melody-plugin" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

grails-melody-plugin

\n

JavaMelody monitoring plugin for Grails 3, to monitor application performance.

\n

Screenshots

\n

The goal of JavaMelody is to monitor applications in QA and production environments. It is not a tool to simulate requests from users, it is a tool to measure and calculate statistics on real operation of an application depending on the usage of the application by users.

\n

Installation

\n

To install the plugin, just add a dependency as given at the top of this page (but runtime is enough instead of compile). For example:

\n
dependencies {\n    runtime 'org.grails.plugins:grails-melody-plugin:1.xx.0'\n}\n
\n

Then you will be able to monitor the application at http://localhost:8080/<YourContext>/monitoring.

\n

\"Download\"

\n

Release Notes

\n

More configuration

\n

A few things you might want to know:

\n\n

All parameters described in the JavaMelody User's guide\ncan be configured in your grails-app/conf/application.yml file. For example, add the following to disable the monitoring:

\n
javamelody:\n    disabled: true\n
\n

JavaMelody uses URIs to resolve HTTP requests. This means that

\n
/book/show/1 and \n/book/show/23 \n
\n

will resolve as different requests. While that's desirable in some cases, often you want the statistics to be gathered for the show action, irrespective of parameters. In that case, add the following configuration in your grails-app/conf/application.yml file and the above URIs will show up as /book/show/$.

\n
javamelody:\n    # filter out numbers from URI\n    http-transform-pattern: \\d+\n
\n

Similar issue may come for SQL monitoring - you can use a similar Regex to filter it.

\n
javamelody:\n    sql-transform-pattern: \\d+\n
\n

Other parameters such as storage-directory, url-exclude-pattern, log, monitoring-path, authorized-users or allowed-addr-pattern can also be configured.

\n

You can also add rules for the spring security plugin, if installed:

\n
grails.plugin.springsecurity.controllerAnnotations.staticRules = [ [pattern: '/monitoring', access: ['ROLE_ADMIN']] ]\n
\n

or add an authorized-users parameter:

\n
javamelody:\n    authorized-users: user1:pwd1, user2:pwd2\n
\n

Please submit github pull requests and github issues.

\n" }, { "bintrayPackage": { "comment": "Only Grails 3.2, 3.3 supported as of 1.2", "name": "memcached-web-plugin", "repo": "plugins", "owner": "purpleraven", "desc": "Store pages of page fragments in memcached", "labels": [ "cache", "memcached" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/purpleraven/grails-memcached-web-plugin/issues", "latestVersion": "1.2", "updated": "2019-12-10T11:11:15.652Z", "systemIds": [ "org.grails.plugins:grails-memcached-web-plugin" ], "vcsUrl": "https://github.com/purpleraven/grails-memcached-web-plugin" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

grails-cows-cache-plugin

\n

\"Download\"

\n

The plugin provides possibility to store pages of page fragments in memcached and use it directly from web servers

\n

thx. to ehcache web for web filter code

\n

Grails 3.2, 3.3 supported

\n

Usage

\n

Base logic:

\n\n

Plugin can be disabled by memcached.disabled=true setting

\n

Controllers actions can be marked by @Memcached(value = 7200, packed = true) annotation or by MemcachedHelper.mark(request, 7200)

\n

cached content can be removed by memcachedService.remove(url) or memcachedService.flush()

\n

SSI for dynamic content supported , see doc

\n
<!--# include virtual="${createLink(controller: 'controller', action: 'action', id:id)}" wait='yes'-->\n
\n

or

\n
<mc:memcachedTile url="${createLink(controller:'controller',action:'action', id:id))}">\n   <span>Content for non-cached page</span>\n</mc:memcachedTile>\n
\n

<mc:memcachedLog/> shows caching time if memcached activated fror the page

\n

Installation

\n

Add the following dependencies in build.gradle

\n
repositories {\n...\n  maven { url "http://dl.bintray.com/purpleraven/plugins" }\n...\n}\ndependencies {\n...\n    compile 'org.grails.plugins:grails-memcached-web-plugin:1.2'\n...\n}\n
\n

In web application config, example for Nginx

\n
\n  upstream app.port {\n    server localhost:8080; # tomcat port\n  }\n  \n  upstream memcached.port {\n    server localhost:11211; # memcached port\n  }\n  \n  # without compression, bug ssi supported\n  location / {\n      ssi on; \n      set $memcached_key "$uri?$args";\n      memcached_pass memcached.port;\n      memcached_gzip_flag 2;\n      default_type text/html;\n      charset utf-8;\n      gunzip on;\n      proxy_set_header Accept-Encoding "gzip";\n      error_page  404 405 400 500 502 503 504 = @fallback;\n    }\n  \n  location @fallback {\n      ssi on;\n      proxy_pass http://app.port;\n      proxy_max_temp_file_size 0;\n      proxy_set_header X-Real-IP $remote_addr;\n      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n      proxy_http_version 1.1;\n      proxy_set_header Connection "";\n      error_page 400 500 502 503 504  /offline.html;\n    }\n  \n  # without compression, ssi NOT supported\n  location /compressed/example {\n    set $memcached_key "$uri?$args";\n    memcached_pass memcached.port;\n    memcached_gzip_flag 2;\n    default_type text/html;\n    charset utf-8;\n    gunzip on;\n    proxy_set_header Accept-Encoding "gzip";\n    error_page  404 405 400 500 502 503 504 = @compressed_fallback;\n  }\n\n  location @compressed_fallback {\n    proxy_pass http://app.port;\n    proxy_max_temp_file_size 0;\n    proxy_set_header X-Real-IP $remote_addr;\n    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n    proxy_http_version 1.1;\n    proxy_set_header Connection "";\n    error_page 400 500 502 503 504  /offline.html;\n  }\n\n\n
\n

License

\n

Apache 2

\n" }, { "deprecated": "This entry in the registry is a duplicate of the entry named 'middleware' by the same author. This entry should probably be removed to avoid confusion.", "bintrayPackage": { "name": "grails-middleware", "repo": "plugins", "owner": "lduarte", "desc": "Grails grails-middleware plugin", "labels": [ "middleware" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/driverpt/grails-middleware/issues", "latestVersion": "0.0.3", "updated": "2016-03-31T13:31:56.173Z", "systemIds": [ "org.grails.plugins:middleware", "org.grails.plugins:grails-middleware" ], "vcsUrl": "https://github.com/driverpt/grails-middleware" }, "documentationUrl": "https://luisduarte.net/grails-middleware/latest/", "mavenMetadataUrl": null, "readme": "

\"Build

\n

Grails Middleware Plugin

\n

See documentation for further information.

\n" }, { "bintrayPackage": { "comment": "Only Grails < 4 supported as of 0.11", "name": "phonenumbers", "repo": "plugins", "owner": "ataylor284", "desc": "Adds support for using Google's libphonenumber library to validate phone numbers", "labels": [ "validation" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/ataylor284/grails-phonenumbers/issues", "latestVersion": "0.11", "updated": "2016-07-21T10:03:35.705Z", "systemIds": [ "ca.redtoad:grails-phonenumbers" ], "vcsUrl": "https://github.com/ataylor284/grails-phonenumbers" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Grails Phonenumbers Plugin

\n

\"Build

\n

This plugin adds phone number validation to grails based on google's\nlibphonenumber (http://code.google.com/p/libphonenumber/) project.

\n

Getting Started

\n

Install the grails plugin. Add the phoneNumber constraint to fields\nof type String to validate them with libphonenumber.

\n
class MyDomain {\n    String phoneNumber\n    static constraints = {\n        phoneNumber(phoneNumber: true)\n    }\n}\n
\n

By default, the validator runs in loose mode. This rejects strings\nthat have obvious problems that would prevent them from being parsed\nas phone numbers.

\n

Region Sensitive Validation

\n

A strict mode is available, uses region specific rules. It ensures\nthat there is at least one region where the phone number is valid.\nStrict mode can be enabled on an individual field as shown below, or\nit can be enabled globally by adding\ngrails.plugins.phonenumbers.defaultStrict = true to Config.groovy.

\n
class MyDomain {\n    String phoneNumber\n    static constraints = {\n        phoneNumber(phoneNumber: [strict: true])\n    }\n}\n
\n

The list of regions can be further restricted, either per-field, or\nglobally, as well. By default, the phone number must be valid in any\nregion supported by libphonenumber. To restrict it to one particular\nregion, or set of regions, the allowRegion can be set to a list of\ntwo-character country codes. To accept only US phone numbers, set\ngrails.plugins.phonenumbers.defaultAllowedRegions = ['US'] in\nConfig.groovy, or set it in the constraint as follows.

\n
class MyDomain {\n    String phoneNumber\n    static constraints = {\n        phoneNumberField(phoneNumber: [strict: true, allowedRegions: ['US']])\n    }\n}\n
\n

Getting the Region at Validation Time

\n

If the region is available in a country field on the domain object, it\ncan be used by the validator dynamically. allowRegions can be set\nto a closure returning a country code or list of country codes. The\nclosure delegate will be the domain object being validated. Example:

\n
class MyDomain {\n    String country\n    String phoneNumber\n    static constraints = {\n        phoneNumber(phoneNumber: [strict: true, allowedRegions: { -> country }])\n    }\n}\n
\n

Formatting Phone Numbers

\n

PhoneNumberService exposes a simple format method for reformatting\nphone number strings. For Example:

\n
class MyDomain {\n    def phoneNumberService\n\n    String phoneNumber\n\n    void setPhoneNumber(String val) {\n        phoneNumber = phoneNumberService?.format(val) ?: val\n    }\n}\n
\n

Phone Number Geolocation

\n

PhoneNumberService also provides a geolocation service that can\ndetermine the country and region from phone number strings. For\nExample:

\n
class MyDomain {\n    def phoneNumberService\n\n    String phoneNumber\n    String geoCountryName\n    String geoCountryCode\n    String geoDescription\n\n    void setPhoneNumber(String val) {\n        phoneNumber = phoneNumberService?.format(val) ?: val\n        def geolocationInfo = phoneNumberService?.geolocate(val)\n        if (geolocationInfo) {\n            geoCountryName = geolocationInfo?.country\n            geoCountryCode = Locale.availableLocales.find { it.displayCountry == geoCountryName }?.country\n            geoDescription = geolocationInfo?.description\n        }\n    }\n}\n
\n

Using PhoneNumberUtil Directly

\n

The phonenumbers plugin publishes the PhoneNumberUtil object as a\nspring bean so it can be autowired into your controllers and services.\nDefine a field called phoneNumberUtil and it will be automatically\ninitialized by spring.

\n
class MyController {\n    def phoneNumberUtil\n}\n
\n

TODO

\n\n

See Also

\n

http://code.google.com/p/libphonenumber

\n" }, { "bintrayPackage": { "name": "pretty-time", "repo": "plugins", "owner": "cazacugmihai", "desc": "A plugin that allows you to display human readable, relative timestamps.", "labels": [ "date" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/cazacugmihai/grails-pretty-time/issues", "latestVersion": "4.0.0", "updated": "2016-03-31T13:31:54.739Z", "systemIds": [ "org.grails.plugins:grails-pretty-time" ], "vcsUrl": "https://github.com/cazacugmihai/grails-pretty-time" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

PrettyTime

\n

PrettyTime is an OpenSource time formatting library. PrettyTime creates human readable, relative timestamps like those seen on Digg, Twitter, and Facebook. It\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffds simple, get started \ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdright now!\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd and in over 25 languages!

\n

This plugin allows you to display human readable, relative timestamps. It is based on PrettyTime OpenSource time formatting library.

\n

Installation

\n
compile ":pretty-time:3.0.2.Final-1.0.0"\n
\n

Installation for 2.x

\n
grails install-plugin pretty-time\nplugins {\n    compile ":pretty-time:2.1.3.Final-1.0.1"\n}\n
\n

Requirements

\n\n

Usage

\n
<prettytime:display date="${someDate}" />\n
\n

outputs:

\n
"right now", "2 days ago", or "3 months from now"\n
\n

Internationalization (I18n)

\n

Build in - uses prettytime library translations. TagLib included in this plugin respects current locale.

\n

Tag attributes

\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
AttributeDescription
dateThe date object to format.
capitalizeCapitalize the output text (default: false). Ex: \"moments ago\" will be capitalized to \"Moments ago\".
showTimeShow the time (default: false). Ex: \"2 days ago, 12:00:25 AM\".
html5wrapperWrap the output text (default: false). Ex: \"moments ago\" will be wrapped with \"<time datetime="some date" title="some date">moments ago</time>\".
formatThe format to use for the date (default: \"hh:mm:ss a\"). The default value is set by \"default.date.format\" in I18n.
\n" }, { "bintrayPackage": { "name": "pushover", "repo": "maven", "owner": "frnktrgr", "desc": "Provides easy access to Pushover API", "labels": [ "pushover", "push-notification" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/frnktrgr/grails-pushover/issues", "latestVersion": "1.0.2", "updated": "2016-12-22T12:27:30.004Z", "systemIds": [ "org.grails.plugins:pushover" ], "vcsUrl": "https://github.com/frnktrgr/grails-pushover" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

grails-pushover

\n

Provides easy access to Pushover API.

\n

Installation

\n

Add following line to dependencies section in build.gradle.

\n
compile 'org.grails.plugins:pushover:1.0.1'\n
\n

Configuration

\n

Add following lines to grails-app/conf/application.yml:

\n
grails:\n\tpushover:\n\t\ttoken: <API_TOKEN>\n\t\tdefaultUser: <DEFAULT_USER>\n
\n

Get your free API Token from Pushover.

\n

The specified token is used in every Pushover call if no explicit token option is given.

\n

If pushoverService.message() is called without a user/group token, the defaultUser is used.

\n

Getting started

\n

Send message to default user

\n

Send message hello world to defaultUser with configured token (see Configuration).

\n
pushoverService.message("hello world")\n
\n

Send message to some user/group

\n

Send message hello world to <USER/GROUP_TOKEN>.

\n
pushoverService.message("hello world", [user: '<USER/GROUP_TOKEN>'])\n
\n

Send message using another API token

\n

Send message hello world using <ANOTHER_API_TOKEN> API token.

\n
pushoverService.message("hello world", [token: '<ANOTHER_API_TOKEN>'])\n
\n

API

\n

All methods and options are named after their Pushover API counterparts. Please read Pushover API.

\n

Send message

\n
pushoverService.message(String message, Map options=[:])\n
\n\n

Retrieve the list of current sounds

\n
pushoverService.sounds(Map options=[:])\n
\n\n

User/Group verification

\n
pushoverService.validateUser(String user, Map options=[:])\n
\n\n

Retrieve information about a group

\n
pushoverService.groups(String group, Map options=[:])\n
\n\n

Adding a user to a group

\n
pushoverService.groupsAddUser(String group, String user, Map options=[:])\n
\n\n

Removing a user from a group

\n
pushoverService.groupsDeleteUser(String group, String user, Map options=[:])\n
\n\n

Temporarily disabling a user in a group

\n
pushoverService.groupsDisableUser(String group, String user, Map options=[:])\n
\n\n

Re-enabling a user in a group

\n
pushoverService.groupsEnableUser(String group, String user, Map options=[:])\n
\n\n

Renaming a group

\n
pushoverService.groupsRename(String group, String name, Map options=[:])\n
\n\n

##TODOs\nSee also https://pushover.net/api

\n\n" }, { "comment": "Only Grails < 4 supported as of 0.7.2", "bintrayPackage": { "name": "quick-search", "repo": "plugins", "owner": "tadodotcom", "desc": "\nSearch plugin for domain class properties. Lightweight plugin which puts the ability for searching, it adds utility\nfunctions for building the search result into a string format representation sufficient for auto-complete as well as\nfunctions for listing the results based on the search query.\n", "labels": [ "search" ], "licenses": [ "BSD" ], "issueTrackerUrl": "https://github.com/tadodotcom/grails-quick-search/issues", "latestVersion": "0.7.2", "updated": "2021-02-22T10:01:03.157Z", "systemIds": [ "org.grails.plugins:grails-quick-search", "grails.plugin:grails-quick-search" ], "vcsUrl": "https://github.com/tadodotcom/grails-quick-search" }, "documentationUrl": "https://tadodotcom.github.io/grails-quick-search/", "mavenMetadataUrl": null, "readme": "

grails-quick-search

\n

Grails plugin for quick search implementation. Supports search for domain class properties and adds utility functions and tag libraries for autocomplete functionality.

\n

Version 0.7.x of this plugin has been upgraded to Grails 3.1.x.

\n

See documentation for further information.

\n" }, { "comment": "Integration with SendGrid is outdated and does not currently seem to work.", "bintrayPackage": { "name": "sendgrid", "repo": "grails-plugins", "owner": "desirable-objects", "desc": "Grails SendGrid Plugin", "labels": [ "mail", "sendgrid" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/desirable-objects/grails-sendgrid/issues", "latestVersion": "2.0.1", "updated": "2016-08-27T11:44:17.969Z", "systemIds": [ "desirableobjects.grails.plugins:grails-sendgrid" ], "vcsUrl": "https://github.com/desirable-objects/grails-sendgrid" }, "documentationUrl": "https://desirable-objects.github.io/grails-sendgrid/", "mavenMetadataUrl": null, "readme": "

grails-sendgrid

\n

\"Slack\n\"Travis

\n

Introduction

\n

The Grails SendGrid plugin allows you to use the services offered by SendGrid to send email from your application.

\n

The plugin works for Grails 3.x. For Grails 2.x please refer to the 1.x branch

\n

Installation

\n

Add the following dependencies in build.gradle

\n
dependencies {\n...\n    compile 'desirableobjects.grails.plugins:grails-sendgrid:2.0.1'\n...\n}\n
\n

Configuration

\n

Configuration takes place in your application's yaml file.

\n

The basic configuration you will need to use the plugin is:

\n
    sendgrid:\n        username: 'your-username'\n        password: 'your-password'\n
\n

Where your-username and your-password should be replaced with your sendgrid login details.

\n

If you need to override the sengrid API endpoint (such as for development/integration environments, to replace it with a fake 'fixture'), you can do that in the same place:

\n
    sendgrid:\n        api:\n            url: 'http://localhost:8080/your-application/fixture/'\n        username: 'your-username'\n        password: 'your-password'\n
\n

Note that your @fixture@ controller must have the 'mail.send.json' action configured, and sending and receiving @application/json@ content, as this is what the plugin expects to call.

\n

Sending Email

\n

In a pinch, you can send email using the SendGridService in one of two ways:

\n\n
sendGridServicesendMail {\n     from 'antony@example.com'\n     to 'aiten@example.net'\n     to 'wirah@example.org'\n     bcc 'yourbcc@example.com'\n     subject 'This is the subject line'\n     body 'This is our message body'\n}\n
\n\n

This is useful when you might want a more programmatic approach to sending email.

\n
SendGridEmail email = new SendGridEmailBuilder()\n                        .from('antony@example.com')\n                        .to('aiten@example.net')\n                        .subject('This is the subject line')\n                        .withText('This is our message body')\n                        .build()\n
\n

When you've built your email, pass it to the SendGridService's send method:

\n
sendGridService.send(email)\n
\n

The email builder is written as a natural-language type DSL, so you might find that there is more than one way to build your email, but under the covers, they are exactly the same.

\n

For further details, see the sendgrid api [http://docs.sendgrid.com/documentation/api/web-api/mail/]

\n" }, { "bintrayPackage": { "name": "shiro", "repo": "plugins", "owner": "nerderg", "desc": "Secure your Grails application quickly and easily using the Apache Shiro security framework.", "labels": [ "security", "shiro" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/nerdErg/grails-shiro/issues", "latestVersion": "4.4", "updated": "2021-04-18T13:56:43.000Z", "systemIds": [ "org.grails.plugins:grails-shiro" ], "vcsUrl": "https://github.com/nerdErg/grails-shiro" }, "documentationUrl": "https://nerderg.com/docs/shiro/guide.html", "mavenMetadataUrl": null, "readme": "
\n
Table of Contents
\n\n
\n
\n
\n
\n

\"Build

\n
\n
\n
\n
\n

Versions

\n
\n
\n
    \n
  • \n

    Latest released versions 3.4, 4.4

    \n
  • \n
  • \n

    Latest working version 3.4, 4.4 (in this repo)

    \n
  • \n
\n
\n
\n

This is the Grails Shiro plugin for grails version 4.0.x and Shiro 1.5.3. This was derived from the Grails 2.x version\n(https://github.com/pledbrook/grails-shiro).

\n
\n
\n

We pretty much re-wrote the plugin for Grails 3 and to simplify the use, improve the documentation and make it easier to\nmaintain. There are lots of changes please check out the\nGuide in the docs directory.

\n
\n
\n

Numbering

\n
\n

In general the version number is following the Grails major version it supports, then release. e.g.

\n
\n
\n
\n
3.4 = Grails 3 plugin release 4\n4.4 = Grails 4 plugin release 4
\n
\n
\n
\n
\n

Maintenance

\n
\n

Although we have now published the Grails 4 version of this plugin we will continue to maintain the Grails 3 version\nbackporting features till July 2020 where possible.

\n
\n
\n
\n

Documentation and Source

\n
\n

In general the documentation applies to both Grails 3 and 4 versions of the plugin. Source code including specific documentation\nfor the Grails 3 version can be found in the Grails-3 Branch.

\n
\n
\n
\n
\n
\n

Installation

\n
\n
\n

To install, add this to your build.gradle dependencies for Grails 4:

\n
\n
\n
\n
compile \"org.grails.plugins:grails-shiro:4.4\"
\n
\n
\n
\n

and this for Grails 3:

\n
\n
\n
\n
compile \"org.grails.plugins:grails-shiro:3.4\"
\n
\n
\n
\n
\n
\n

Getting started

\n
\n
\n

If you’re implementing your security from scratch, then you can simply install grails-shiro by adding

\n
\n
\n
\n
compile \"org.grails.plugins:grails-shiro:4.4\"
\n
\n
\n
\n

to your build.gradle dependencies and typing\nshiro quick start, 'grails shiro-quick-start'.

\n
\n
\n

This will create a ShiroWildcardDbRealm in your grails-app/realms directory and make a ShiroUser and ShiroRole domain\nclass. It will also create an AuthController to let you log in. Check out\nWildcard DB Realm for how you might populate\na couple of users using Boostrap.groovy.

\n
\n
\n

Now to Control access to a Controller add an Interceptor for that controller using\ngrails create-shiro-controller-interceptor MyController which will add\naccess control by convention.

\n
\n
\n
\n
\n

Version change log

\n
\n
\n

version 4.4

\n
\n
    \n
  • \n

    Upgrade shiro to version 1.7.1 fixing CVE-2020-17523

    \n
  • \n
\n
\n
\n
\n

version 3.3 & 4.3

\n
\n\n
\n
\n\n\n\n\n\n
\n
Warning
\n
\nThis introduces a small breaking change. Annotations now use the login and unauthorized settings not URL Mappings\nto set where they redirect to.\n
\n
\n
\n
\n

version 4.2

\n
\n
    \n
  • \n

    upgrade to shiro 1.4.2

    \n
  • \n
\n
\n
\n
\n

version 4.1

\n
\n
    \n
  • \n

    ported to Grails version 4.0.0 (thanks Peter Legen/animator013 for you help!)

    \n
  • \n
\n
\n
\n
\n

version 3.1

\n
\n
    \n
  • \n

    Added ability to set the remember me cipherKey or the length of the randomly generated key

    \n
  • \n
  • \n

    Fix for onNotAuthenticated and onUnauthorized not working correctly (Can’t be invoked on metaclass)

    \n
  • \n
\n
\n
\n
\n

version 3.0

\n
\n
    \n
  • \n

    re-write from old Grails 2 plugin see updates in the Guide

    \n
  • \n
\n
\n
\n
\n
\n
\n

Building from source

\n
\n
\n

To build the plugin yourself and install it from this repo:

\n
\n
\n
    \n
  1. \n

    clone or fork this repo to your machine

    \n
  2. \n
  3. \n

    run gradle install and that will build, test, install it to your local maven repo (~/.m2)

    \n
  4. \n
  5. \n

    profit!

    \n
  6. \n
\n
\n
\n
\n
\n

Publishing

\n
\n
\n

If you have the credentials to publish the plugin just run the gradle bintrayUpload task.

\n
\n
\n
\n
\n

Kudos

\n
\n
\n\n
\n
\n

Thank you to everyone who provides feedback!

\n
\n
\n
" }, { "bintrayPackage": { "name": "spring-websocket", "repo": "maven", "owner": "zyro", "desc": "This plugin aims at making the websocket support introduced in Spring 4.0 available to Grails applications.", "labels": [ "websocket" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/zyro23/grails-spring-websocket/issues", "latestVersion": "2.5.0.RC1", "updated": "2020-07-06T19:52:50.415Z", "systemIds": [ "org.grails.plugins:grails-spring-websocket" ], "vcsUrl": "https://github.com/zyro23/grails-spring-websocket" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Spring Websocket Grails Plugin

\n

This plugin aims at making the websocket support introduced in Spring 4.0 available to Grails applications.

\n

You can also use the corresponding Spring docs/apis/samples as a reference.

\n

That is mentioned multiple times in this readme because there is everything explained in fine detail.

\n

Grails version requirements:

\n\n \n \n \n \n \n \n \n \n \n \n \n \n
grails-spring-websocketGrails
2.4.x3.2.7+
2.5.x4.0.0+
\n

Installation

\n

To install the plugin into a Grails application add the following line to your build.gradle dependencies section:

\n
implementation "org.grails.plugins:grails-spring-websocket:2.5.0.RC1"\n
\n

The plugin is published to bintray, and linked to grails/plugins as well as jcenter.

\n

Usage

\n

The plugin makes the Spring websocket/messaging web-mvc annotations useable in Grails, too.

\n

Those annotations can be used in:

\n\n

I think basic usage is explained best by example code.

\n

But: the code below is just some very minimal it-works proof.

\n

Check the Spring docs/apis/samples for more advanced use-cases, e.g. security and authentication.

\n

Controller (annotated handler method)

\n

/grails-app/controllers/example/ExampleController.groovy:

\n
package example\n\nimport org.springframework.messaging.handler.annotation.MessageMapping\nimport org.springframework.messaging.handler.annotation.SendTo\n\nclass ExampleController {\n\n    def index() {}\n\n    @MessageMapping("/hello")\n    @SendTo("/topic/hello")\n    protected String hello(String world) {\n        return "hello, ${world}!"\n    }\n\n}\n
\n

Unless you want your handler method to be exposed as a Grails controller action, you should define the annotated method as protected or add an additional annotation @grails.web.controllers.ControllerMethod.

\n

Alternatively, WebSocket Grails artefacts and/or Spring @Controller beans can be used as well, for example:

\n

/grails-app/websockets/example/ExampleWebSocket.groovy:

\n
package example\n\nimport org.springframework.messaging.handler.annotation.MessageMapping\nimport org.springframework.messaging.handler.annotation.SendTo\n\nclass ExampleWebSocket {\n\n    @MessageMapping("/hello")\n    @SendTo("/topic/hello")\n    String hello(String world) {\n        return "hello, ${world}!"\n    }\n\n}\n
\n

Client-side (webstomp.js)

\n

/grails-app/views/example/index.gsp:

\n
<!DOCTYPE html>\n<html>\n    <head>\n        <meta name="layout" content="main"/>\n\n        <asset:javascript src="application" />\n        <asset:javascript src="spring-websocket" />\n\n        <script type="text/javascript">\n             $(function() {\n                var socket = new SockJS("${createLink(uri: '/stomp')}");\n                var client = webstomp.over(socket);\n\n                client.connect({}, function() {\n                    client.subscribe("/topic/hello", function(message) {\n                        $("#helloDiv").append(message.body);\n                    });\n                });\n\n                $("#helloButton").click(function() {\n                    client.send("/app/hello", JSON.stringify("world"));\n                });\n            });\n        </script>\n    </head>\n    <body>\n        <button id="helloButton">hello</button>\n        <div id="helloDiv"></div>\n    </body>\n</html>\n
\n

This would be the index view of the controller above. The js connects to the message broker and subscribes to /topic/hello.

\n

For this example, I added a button allowing to trigger a send/receive roundtrip.

\n

While this example shows jquery used with the asset-pipeline plugin, the use of jquery is not required.

\n

Service (brokerMessagingTemplate bean)

\n

To send messages directly, the brokerMessagingTemplate bean (of type SimpMessageSendingOperations) can be used.

\n

The plugin provides a WebSocket trait that autowires the brokerMessagingTemplate and delegates to it.

\n

That WebSocket trait is automatically implemented by WebSocket artefacts but you can implement it from other beans as well, e.g. from a service.

\n

/grails-app/services/example/ExampleService.groovy:

\n
package example\n\nimport grails.plugin.springwebsocket.WebSocket\n\nclass ExampleService implements WebSocket {\n\n    void hello() {\n        convertAndSend "/topic/hello", "hello from service!"\n    }\n\n}\n
\n

Or, if you prefer, you can also inject and use the brokerMessagingTemplate bean directly.

\n

/grails-app/services/example/ExampleService.groovy:

\n
package example\n\nimport org.springframework.messaging.simp.SimpMessageSendingOperations\n\nclass ExampleService {\n\n    SimpMessageSendingOperations brokerMessagingTemplate\n\n    void hello() {\n        brokerMessagingTemplate.convertAndSend "/topic/hello", "hello from service!"\n    }\n\n}\n
\n

Configuration

\n

Configuration relies on Spring java config, especially @EnableWebSocketMessageBroker.

\n

Default Configuration

\n

By default, a configuration bean named webSocketConfig of type grails.plugin.springwebsocket.DefaultWebSocketConfig is used.

\n\n

If the default values are fine for your application, you are good to go. No configuration required then.

\n

Custom Configuration

\n

If you want to customize the defaults, you should override the config bean providing your own bean named webSocketConfig.

\n

As starting point, you can create a config class/bean very similar to the default config with:

\n
grails create-web-socket-config my.package.name.MyClassName\n
\n

That class will be placed under src/main/groovy and needs to be registered as a Spring bean named webSocketConfig, e.g. like this:

\n

/grails-app/conf/spring/resources.groovy:

\n
beans = {\n    webSocketConfig my.package.name.MyClassName\n}\n
\n

From there, check the Spring docs/apis/samples for the available configuration options.

\n

Full-Featured Broker

\n

To use a full-featured (e.g. RabbitMQ, ActiveMQ, etc.) instead of the default simple broker, please refer to the Spring docs regarding configuration.\nAdditionally, add two dependencies for TCP connection management.

\n
implementation platform("io.netty:netty-bom:4.1.34.Final")\nimplementation platform("io.projectreactor:reactor-bom:Californium-SR6")\nimplementation "io.netty:netty-all"\nimplementation "io.projectreactor.netty:reactor-netty"\n
\n

It is a good idea to align the BOM versions with the ones your current spring-boot BOM is using.

\n

User Destinations

\n

To send messages to specific users, you can (among other ways) annotate message handler methods with @SendToUser and/or use the SimpMessagingTemplate.convertAndSendToUser(...) methods.

\n

/grails-app/controllers/example/ExampleController.groovy:

\n
class ExampleController {\n\n    @MessageMapping("/hello")\n    @SendToUser("/queue/hello")\n    protected String hello(String world) {\n        return "hello from controller, ${world}!"\n    }\n\n}\n
\n

To receive messages for the above /queue/hello user destination, the js client would have to subscribe to /user/queue/hello.

\n

If a user is not logged in, @SendToUser will still work and only the user who sent the ingoing message will receive the outgoing one returned by the method.

\n

/grails-app/services/example/ExampleService.groovy:

\n
class ExampleService implements WebSocket {\n\n    void hello() {\n        convertAndSendToUser("myTargetUsername", "/queue/hello", "hello, target user!")\n    }\n\n}\n
\n

Again, to receive messages for the above /queue/hello user destination, the js client would have to subscribe to /user/queue/hello.

\n

Security

\n

To secure websocket messaging, we can leverage the first-class websocket security support of Spring Security 4.0+.

\n

Check the Spring Security docs and the Spring Guides to get a jump-start into the topic.

\n

There is a variety of options how to build your solution, including:

\n\n

I will only show a short example of securing message handler methods with security annotations and filtering inbound messages. I hope you do not mind the lack of import statements in the following code snippets ;)

\n

A working Spring Security setup is required. For the sake of brevity, here a super-minimalistic Spring Security dummy configuration:

\n

/build.gradle:

\n
dependencies {\n    implementation "org.springframework.security:spring-security-config"\n    implementation "org.springframework.security:spring-security-messaging"\n    implementation "org.springframework.security:spring-security-web"\n}\n
\n

/src/main/groovy/example/WebSecurityConfig.groovy:

\n
@Configuration\n@EnableGlobalMethodSecurity(prePostEnabled = true)\n@EnableWebSecurity\nclass WebSecurityConfig extends WebSecurityConfigurerAdapter {\n\n    @Override\n    protected void configure(HttpSecurity http) throws Exception {\n        http.httpBasic()\n        http.authorizeRequests().anyRequest().authenticated()\n    }\n\n    @Autowired\n    void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {\n        auth.inMemoryAuthentication()\n            .withUser("user").password("password").roles("USER")\n    }\n\n}\n
\n

Spring security will by default enable CSRF protection for websocket messages.

\n

To include the required token in the stomp headers, your js code could look like this:

\n

/grails-app/views/example/index.gsp:

\n
$(function() {\n    var url = "${createLink(uri: '/stomp')}";\n    var csrfHeaderName = "${request._csrf.headerName}";\n    var csrfToken = "${request._csrf.token}";\n    var socket = new SockJS(url);\n    var client = webstomp.over(socket);\n    var headers = {};\n    headers[csrfHeaderName] = csrfToken;\n    client.connect(headers, function() {\n        // subscriptions etc. [...]\n    });\n});\n
\n

There are still embedded GSP GString expressions present, which means that snippet will only work in a GSP as-is. If you plan on extracting the js properly into an own js file (or similar), you will have to pass those values along.

\n

Securing Message Handler Methods

\n

Securing message handler methods can be achieved with annotations in a declarative fashion.

\n

The following example shows a Grails controller with a secured message handler method and an message exception handler method.

\n

/grails-app/controllers/example/ExampleController.groovy:

\n
class ExampleController {\n\n    @ControllerMethod\n    @MessageMapping("/hello")\n    @PreAuthorize("hasRole('ROLE_USER')")\n    @SendTo("/topic/hello")\n    String hello(String world) {\n        return "hello from secured controller, ${world}!"\n    }\n    \n    @ControllerMethod\n    @MessageExceptionHandler\n    @SendToUser(value = "/queue/errors", broadcast = false)\n    String handleException(Exception e) {\n        return "caught ${e.message}"\n    }\n    \n}\n
\n

Besides the security handling itself, this snippet shows one important catch: if you want to secure Grails controller actions with @PreAuthorize, the secured method has to be public. However, as we still do not want the method to be exposed as a controller action but only as message handler, in this case the use of @ControllerMethod is required.

\n

If you use Grails WebSocket artefacts or Spring @Controller beans as message handlers, you do obviously not require those additional @ControllerMethod annotations.

\n

Filtering messages

\n

The following example shows how you can filter inbound messages by type and/or by destination pattern.

\n

/src/main/groovy/example/WebSecurityConfig.groovy:

\n
@Configuration\nclass WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {\n    \n    @Override\n    void configureInbound(MessageSecurityMetadataSourceRegistry messages) {\n        messages\n            .nullDestMatcher().authenticated()\n            .simpSubscribeDestMatchers("/user/queue/errors").permitAll()\n            .simpDestMatchers("/app/**").hasRole("USER")\n            .simpSubscribeDestMatchers("/user/**", "/topic/**").hasRole("USER")\n            .simpTypeMatchers(SimpMessageType.MESSAGE, SimpMessageType.SUBSCRIBE).denyAll()\n            .anyMessage().denyAll()\n    }\n    \n}\n
\n

Event Handling

\n

Starting with Grails 3, grails-plugin-events is a core plugin allowing to use the Reactor framework for event handling.

\n

While there is no special event integration regarding websocket messaging (because it is not really necessary anymore), a service that handles application events can look like the follwing snippet. I am not talking about Spring ApplicationEvents here, but Reactor Events.

\n

/grails-app/services/example/ExampleService.groovy:

\n
@Consumer\nclass ExampleService implements WebSocket {\n    \n    @Selector("myEvent")\n    void hello(Event<String> event) {\n        convertAndSend("/topic/myEventTopic", "myEvent: ${event.data}")\n    }\n    \n}\n
\n

Events can be fired/sent from all application artefacts/beans that implement the trait Events. Grails service beans do so by convention. Those beans also allow dynamic registration of event listeners. E.g.:

\n

/grails-app/services/example/ExampleService.groovy:

\n
class ExampleService {\n    \n    void fireMyEvent() {\n        notify "myEvent", "hello from myEvent!"\n    }\n    \n}\n
\n

/grails-app/init/BootStrap.groovy:

\n
class BootStrap implements Events, WebSocket {\n\n    def init = {\n        on("myEvent") { Event<String> event ->\n            convertAndSend("/topic/myEventTopic", "myEvent: ${event.data}")\n        }\n    }\n\n}\n
\n

For further information check the Grails async docs.

\n

Misc

\n

Startup performance

\n

Scanning Grails controllers for message handler methods can impact application startup time if you have many controllers.

\n

One way around this is to put your message handler methods into Grails WebSocket artefacts instead of Grails controllers and then use a custom websocket config class without the GrailsSimpAnnotationMethodMessageHandler.

\n" }, { "bintrayPackage": { "name": "twilio", "repo": "plugins", "owner": "novadge", "desc": "Provides SMS sending capabilities to a Grails application.", "labels": [ "twilio", "sms" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/Novadge/grails-twilio/issues", "latestVersion": "0.1.4", "updated": "2016-08-13T23:01:56.281Z", "systemIds": [ "org.grails.plugins:grails-twilio", "com.novadge.plugins:grails-twilio" ], "vcsUrl": "https://github.com/Novadge/grails-twilio" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Twilio Grails

\n

Description

\n

The twilio-grails plug-in provides sms sending capability to a Grails application via twilio api.

\n

Configuration

\n

Add your twilio properties to grails configuration file: Example\nAssuming you have a twilio account, then add the required information to your grails config file.

\n\n
twilio {\n    // Enter your host address\n    host = 'https://api.twilio.com'\n    apiID = 'enter your api Id'\n    apiPass = 'enter your api password'\n    smsUrl = '/2010-04-01/Accounts/' + apiID + '/Messages.json'\n    number = ""\n}\n
\n
\n

BuildConfig.groovy

\nCopy and paste the following to your BuildConfig.groovy File\n\ncompile(group:'org.apache.httpcomponents',name:'httpclient',version:'4.3.6')\n compile(group:'org.apache.httpcomponents',name:'fluent-hc',version:'4.3.6')\n compile(group:'org.apache.httpcomponents',name:'httpclient-cache',version:'4.3.6')\n compile(group:'org.apache.httpcomponents',name:'httpmime',version:'4.3.6')\n\n

Usage

\n

Inject smsService into your class

\n

def smsService

\n

smsService is a Grails service that provides a method called send() that can take mapped parameters.\nPlease note that 'send()' is overloaded 'see http://en.wikipedia.org/wiki/Function_overloading' and can take various variations of parameters.

\n
\nOne simple form is:\n\nsend(Map map)\n\n

Where ......

\n

map contains parameters...\nmap.to: phone number of recipient eg +1234444444

\n

map.from: your twilio assigned number eg. +09899898989

\n

map.body: "The body of your message"\nmap.mediaUrl: "Url for any attachment" (optional )

\n

Example

\n

An example usage can be seen below.

\n\n
Class YourController{\n \n    def smsService\n    ...\n    def yourMethod(){\n        def map = [to:"070987878787",from:"09808000000",body:"SMS BODY"]\n        smsService.send(map)\n    \n    }\n\n}\n
\n
\n" }, { "bintrayPackage": { "name": "vaadin", "repo": "plugins", "owner": "ondrej-kvasnovsky", "desc": "Vaadin plugin for Grails.", "labels": [ "vaadin" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/ondrej-kvasnovsky/grails-vaadin-plugin", "latestVersion": "2.0.3", "updated": "2018-03-09T04:04:10.013Z", "systemIds": [ "com.vaadinongrails:grails-vaadin-plugin" ], "vcsUrl": "https://github.com/ondrej-kvasnovsky/grails-vaadin-plugin" }, "documentationUrl": "https://ondrej-kvasnovsky.github.io/grails-vaadin-plugin/", "mavenMetadataUrl": null, "readme": "

Welcome to the official source code repository of grails-vaadin plugin.

\n

Vaadin on Grails Book

\n

vaadinongrails.com

\n

Twitter @VaadinOnGrails

\n" }, { "displayName": "json-views", "bintrayPackage": { "name": "grails-views", "repo": "plugins", "owner": "grails", "desc": "Grails JSON Views", "labels": [ "json", "rest", "views" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails/grails-views/issues", "latestVersion": "3.2.3", "updated": "2024-04-04T11:02:57.000Z", "systemIds": [ "org.grails.plugins:views-json" ], "vcsUrl": "https://github.com/grails/grails-views" }, "documentationUrl": "https://views.grails.org/latest/#_json_views", "mavenMetadataUrl": "https://repo1.maven.org/maven2/org/grails/plugins/views-json/maven-metadata.xml", "readme": "

Grails Views

\n

Additional View Technologies for Grails 3.0 and above.

\n

Initial implementation includes JSON views powered by Groovy's JsonBuilder, however this project provides the basis for implementation other view types.

\n

View the latest documentation for details.

\n

\"Java

\n" }, { "bintrayPackage": { "name": "x-frame-options-plugin", "repo": "plugins", "owner": "mrhaki", "desc": "Servlet filter that adds a X-FRAME-OPTIONS response header", "labels": [ "security" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/mrhaki/grails-x-frame-options-plugin/issues", "latestVersion": "1.1.0", "updated": "2017-03-09T10:57:09.659Z", "systemIds": [ "org.grails.plugins:x-frame-options", "org.grails.plugins:grails-x-frame-options-plugin" ], "vcsUrl": "https://github.com/mrhaki/grails-x-frame-options-plugin" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "
\n

Grails X-Frame-Options Plugin

\n
\n
\n

Filter to set HTTP response header X-Frame-Options to defend against\nClickJacking.

\n
\n
\n

More information about using X-Frame-Options for defending against clickjacking:

\n
\n\n
\n
\n
\n

Installation

\n
\n
\n

These instructions are targeted towards Grails 3 installations. For Grails 2.x refer to branch 1.x of the plugin.

\n
\n
\n

Add a dependency to build.gradle:

\n
\n
\n
\n
...\ndependencies {\n    ...\n    runtime ('org.grails.plugins:x-frame-options:1.1.2')\n    ...\n}\n...
\n
\n
\n
\n

The default configuration installs a servlet filter for the URL pattern /* that adds a response\nheader X-Frame-Options with the value DENY.

\n
\n
\n
\n
\n

Configuration

\n
\n
\n

The plugin is configured through grails-app/conf/application.yml.

\n
\n
\n

We can limit the URL pattern the filter is applied to:

\n
\n
\n
\n
grails:\n    plugin:\n        xframeoptions:\n            urlPattern: /path/*
\n
\n
\n
\n

We can also set multiple patterns:

\n
\n
\n
\n
grails:\n    plugin:\n        xframeoptions:\n            urlPattern:\n                - /path/*\n                - /other/*
\n
\n
\n
\n

We can set different header values based on the configuration.\nTo set the header value DENY we must use the following configuration:

\n
\n
\n
\n
grails:\n    plugin:\n        xframeoptions:\n            deny: true
\n
\n
\n
\n

This is also the default value if no configuration is provided or no configuration options\nare set.

\n
\n
\n

To set the header value SAMEORIGIN we must use the following configuration:

\n
\n
\n
\n
grails:\n    plugin:\n        xframeoptions:\n            sameOrigin: true
\n
\n
\n
\n

To set the header value ALLOW-FROM with a URL we must use the following configuration:

\n
\n
\n
\n
grails:\n    plugin:\n        xframeoptions:\n            allowFrom: http://www.mrhaki.com
\n
\n
\n
\n

To disable the filter we must use the following configuration option:

\n
\n
\n
\n
grails:\n    plugin:\n        xframeoptions:\n            enabled: false
\n
\n
\n
\n

The filter is enabled by default and will use the DENY header value.

\n
\n
\n
" }, { "deprecated": "Since version 3.2.1, Grails has built-in CORS support.", "bintrayPackage": { "name": "cors-interceptor", "repo": "maven", "owner": "appcela", "desc": "Add Cross-Origin Resource Sharing (CORS) headers for Grails 3 applications.", "labels": [ "cors" ], "licenses": [ "MIT" ], "issueTrackerUrl": "https://github.com/appcela/grails3-cors-interceptor/issues", "latestVersion": "1.2.1", "updated": "2017-11-07T07:26:53.951Z", "systemIds": [ "org.grails.plugins:grails3-cors-interceptor" ], "vcsUrl": "https://github.com/appcela/grails3-cors-interceptor" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

grails3-cors-interceptor

\n

Add Cross-Origin Resource Sharing (CORS) headers for Grails 3 applications.

\n

Grails 3.2.2+

\n

For Grails 3.2.2+, please use the Grails built-in CORS support, you no longer need this plugin.

\n

Grails 3.0.x - 3.2.1 Only

\n

This plugin will add a new Interceptor (see Grails 3 Interceptor API) to your Grails app that adds CORS headers to all your controllers and actions.

\n

This plugin has only been tested with Grails 3.0., 3.0.15, 3.1.4 and 3.2.0, 3.2.1

\n\n

Grails 2.x

\n

For Grails 2.x app, please use the execellent CORS Plugin. In fact, this plugin is based on the Grails 3 servlet filter code provided in the README by that plugin author. The filter code is rewritten as interceptor for this plugin.

\n

Usage

\n

1. Add Plugin Dependency

\n

Add the following dependency to your Grails app,

\n

build.gradle

\n
compile "org.grails.plugins:grails3-cors-interceptor:1.2.1"\n
\n

2. (Optional) Add HTTP OPTIONS Method URL Mapping

\n

For Grails 3.1.4+, this step is no longer needed. Please skip it.

\n

To support the preflight CORS request with HTTP OPTIONS method, url mappings for OPTIONS method must be added explicitly.

\n

UrlMappings.groovy

\n
"/books"(resources:'book') // mapping to REST resource "book"\n"/books/$id?"(controller:'book', method: 'OPTIONS') // explicitly map OPTIONS method to "book" REST controller\n
\n

3. (Optional) Configuration Settings

\n

application.yml

\n
corsInterceptor:\n    includeEnvironments: ['development', 'test']\n    excludeEnvironments: ['production']\n    allowedOrigins: ['yourhost.com']\n    allowedHeaders: ['my-authorization-header', 'origin', 'content-type', 'accept']\n
\n\n

Working with Spring Security Core or Spring Security REST Plugins

\n

See the sample app grails3-cors-interceptor-spring-security-rest-sample-app for detailed\ninstructions on how to get grails3-cors-interceptor working with Spring Security Core or Spring Security REST plugin.

\n" }, { "bintrayPackage": { "name": "uploadr", "repo": "plugins", "owner": "pankajtandon", "desc": "Plugin to upload multiple files from a web page. Uses HTML5 and CSS3", "labels": [ "upload" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/pankajtandon/grails3-uploadr/issues", "latestVersion": "3.1.0", "updated": "2016-06-11T13:54:37.345Z", "systemIds": [ "com.nayidisha.grails.uploadr:grails3-uploadr" ], "vcsUrl": "https://github.com/pankajtandon/grails3-uploadr" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

HTML5 and CSS3 based File Uploader

\n

About

\n

Grails 3 is based on Spring-Boot and plugins written pre-Grails 3 have to be "re-structured" or re-configured for Grails 3.

\n

This is an upgrade to grails 3.x of the excellent plugin written by Dustin Clark here

\n

Usage

\n

In the project that you would like to use the uploadr plugin, include the following in its build.gradle.

\n
\nbuildscript {\n...\n    dependencies {\n        classpath 'com.bertramlabs.plugins:asset-pipeline-gradle:2.5.0'\n        ...\n    }\n}\n
\n

and

\n
\ndependencies {\n ...\n    compile \"com.nayidisha.grails.uploadr:grails3-uploadr:3.0\"\n...\n}\n
\n

Then in a gsp where the uploadr needs to be installed:

\n
<!DOCTYPE HTML>\n<html>\n<head>\n    ...\n    <asset:javascript src="uploadr.manifest.js"/>\n    <asset:javascript src="uploadr.demo.manifest.js"/>\n    <asset:stylesheet href="uploadr.manifest.css"/>\n    <asset:stylesheet href="uploadr.demo.manifest.css"/>\n    ...\n</head>\n<body>\n    ...\n    <uploadr:demo/>\n    ...\n</body>\n</html>\n
\n

Images

\n

When your gsp is configured with a tag like so:

\n
<uploadr:add name="aFileToUpload.png" path="/somewhereOnYourFS" maxSize="52428800" />\n
\n

Here is how a single file upload looks:

\n

\"uploadImage\"

\n

and after upload...

\n

\"uploadImage\"

\n

ToDo

\n\n" }, { "bintrayPackage": { "name": "gravatar", "repo": "plugins", "owner": "rpalcolea", "desc": "Grails plugin for displaying avatars from Gravatar", "labels": [ "gravatar", "image" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/rpalcolea/grails-gravatar/issues", "latestVersion": "1.0.2", "updated": "2016-09-04T02:11:13.186Z", "systemIds": [ "rpalcolea.gravatar:gravatar" ], "vcsUrl": "https://github.com/rpalcolea/grails-gravatar" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Grails Gravatar Plugin

\n

\"Build\n\"Download\"\n\"Slack

\n

This plugin provides a taglib for displaying gravatars.

\n

Gravatars allow users to configure an avatar to go with their email address at a central location: gravatar.com. Gravatar-aware websites can then look up and display each user\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffds preferred avatar, without having to handle avatar management. The user gets the benefit of not having to set up an avatar for each site that they post on.

\n

Installation

\n

Add the following dependencies in build.gradle

\n
dependencies {\n...\n    compile 'rpalcolea.gravatar:gravatar:1.0.2'\n...\n}\n
\n

Configuration

\n

You can modify the default rating and defaultImage in your application.yml as follows

\n
gravatar:\n    defaultRating: g #Optional (default is g)\n    defaultGravatarUrl: http://docs.grails.org/latest/img/grails.png #optional\n
\n

Usage

\n

###TagLib\nUsing the taglib is simple:

\n
<gravatar:image email="roberto@perezalcolea.info"/>\n
\n

This will output

\n
<img id="" name="" alt="Gravatar" class="gravatar" height="80" width="80" src="https://www.gravatar.com/avatar/ae03f5244dfbbd216864590baacfd130?s=80&r=g" title="gravatar"/>\n
\n

You can provide the following arguments to the TagLib:

\n
 /**\n     * @attr email    REQUIRED\tthe startDate for styling\n     * @attr size          the disired dimensions in pixels for the gravatar image (from 1 up to 512)\n     * @attr alt          alt-attribute for the resulting img-element\n     * @attr cssClass        class-attribute for the resulting img-element\n     * @attr title          title-attribute for the resulting img-element\n     * @attr id            id-attribute for the resulting img-element\n     * @attr name          name-attribute for the resulting img-element\n     * @attr defaultGravatarUrl    the default image to display if no gravatar is found; may be a URL or one of the following (defaults to the official Gravatar logo):\n     * \t\t\t\t\t\t\t\t<li>404: do not load any image if none is associated with the email hash, instead return an HTTP 404 (File Not Found) response\n     * \t\t\t\t\t\t\t\t<li>mm: (mystery-man) a simple, cartoon-style silhouetted outline of a person (does not vary by email hash)\n     * \t\t\t\t\t\t\t\t<li>identicon: a geometric pattern based on an email hash\n     * \t\t\t\t\t\t\t\t<li>monsterid: a generated 'monster' with different colors, faces, etc\n     * \t\t\t\t\t\t\t\t<li>wavatar: generated faces with differing features and backgrounds\n     * \t\t\t\t\t\t\t\t<li>retro: awesome generated, 8-bit arcade-style pixelated faces\n     * @attr gravatarRating      desired image rating censor-level; may be one of the following:\n     * \t\t\t\t\t\t\t\t<li>g (default): suitable for display on all websites with any audience type.\n     * \t\t\t\t\t\t\t\t<li>pg: may contain rude gestures, provocatively dressed individuals, the lesser swear words, or mild violence.\n     * \t\t\t\t\t\t\t\t<li>r: may contain such things as harsh profanity, intense violence, nudity, or hard drug use.\n     * \t\t\t\t\t\t\t\t<li>x: may contain hardcore sexual imagery or extremely disturbing violence.\n     */\n
\n

###GravatarUrlGenerator\nIf you want to generate links without the use of the taglib, you can accomplish it by using GravatarUrlGenerator as follows:

\n
GravatarUrlGenerator.generateUrl('roberto@perezalcolea.info')\n
\n

This will output

\n
https://www.gravatar.com/avatar/ae03f5244dfbbd216864590baacfd130?s=80&r=g\n
\n

You can provide the following arguments:

\n
  GravatarRating rating\n  Integer size\n  String defaultImage\n
\n

Acknowledgements

\n

This plugin contains original code and the ideas from the Avatar Plugin for Grails 1.x by Domingo Suarez Torres (@domix)

\n

License

\n

Apache 2

\n

Sponsors

\n

\"Alt

\n

YourKit supports open source projects with its full-featured Java Profiler.\nYourKit, LLC is the creator of YourKit Java Profiler\nand YourKit .NET Profiler,\ninnovative and intelligent tools for profiling Java and .NET applications.

\n" }, { "bintrayPackage": { "name": "greenmail", "repo": "plugins", "owner": "gpc", "desc": "Grails GreenMail Plugin", "labels": [ "testing", "mail" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/gpc/greenmail/issues", "latestVersion": "2.0.0.RC3", "updated": "2021-02-24T01:09:42.561Z", "systemIds": [ "org.grails.plugins:greenmail" ], "vcsUrl": "https://github.com/gpc/greenmail" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Greenmail Plugin for Grails 3

\n

This is a fork of grails greenmail plugin for grails 3.

\n

INSTALL

\n

Add a dependency for the plugin in build.gradle:

\n
\ndependencies {    \n    compile 'org.grails.plugins:greenmail:2.0.0.RC2'    \n}\n\n
\n

USAGE

\n

Provides a wrapper around GreenMail and provides a view that displays sent messages - useful for testing application in the development or test environments.

\n

Installation

\n
grails install-plugin greenmail\n
\n

The plugin assumes that you have some sort of Java mail provider installed (for instance the Grails mail plugin). You need to define a SMTP port for the mock Greenmail SMTP server to start with. Using the Grails Mail plugin, this is as simple as defining the grails.mail.port property in Config.groovy, like this (see the first line in the development and test blocks):

\n
environments {\n    production {\n        grails.serverURL = "http://www.changeme.com"\n    }\n    development {\n\tgrails.mail.port = com.icegreen.greenmail.util.ServerSetupTest.SMTP.port\n        grails.serverURL = "http://localhost:8080/${appName}"\n    }\n    test {\n\tgrails.mail.port = com.icegreen.greenmail.util.ServerSetupTest.SMTP.port\n        grails.serverURL = "http://localhost:8080/${appName}"\n    }\n}\n
\n

You can also completely disable the plugin by using the config setting grails.plugin.greenmail.disabled = true. For example, to disable greenmail in production:

\n
environments {\n    production {\n       grails.plugin.greenmail.disabled=true\n    }\n}\n
\n

If you need to change the default listening port (1025) you can use the grails.plugin.greenmail.ports.smtp configuration variable. For example:

\n
environments {\n    test {\n       grails.plugin.greenmail.ports.smtp = 2025\n    }\n}\n
\n

Usage in Integration Tests

\n

The plugin can be used to capture email messages during integration tests. For example:

\n
import com.icegreen.greenmail.util.*\n\nclass GreenmailTests extends GroovyTestCase {\n    def mailService\n    def greenMail\n\n    void testSendMail() {\n        Map mail = [message:'hello world', from:'from@piragua.com', to:'to@piragua.com', subject:'subject']\n\n        mailService.sendMail {\n            to mail.to\n            from mail.from\n            subject mail.subject\n            body mail.message\n        }\n        \n        assertEquals(1, greenMail.getReceivedMessages().length)\n\t\n        def message = greenMail.getReceivedMessages()[0]\n\t\t\n        assertEquals(mail.message, GreenMailUtil.getBody(message))\n        assertEquals(mail.from, GreenMailUtil.getAddressList(message.from))\n        assertEquals(mail.subject, message.subject)\n    }\n\n    void tearDown() {\n        greenMail.deleteAllMessages()\n    }\n}\n
\n

The plugin adds a deleteAllMessages() convenience method to the greenMail bean that deletes all received messages.

\n

Usage in running application

\n

The plugin provides a controller and view to show messages that are sent from the application. Simply browse to http://localhost:8080/greenmail and it will show a list of messages sent. You can click on the show link to view the raw message.

\n

Roadmap

\n

This is a fully functional plugin, though there are some features that I think would be worth adding. Contributions and patches are welcome!

\n\n" }, { "bintrayPackage": { "name": "gsp", "repo": "plugins", "owner": "grails", "desc": "Grails Server Pages (GSP) - GSP (Grails Server Pages) - A server-side view rendering technology based on Groovy", "labels": [ "views" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails/grails-gsp/issues", "latestVersion": "6.2.3", "updated": "2024-10-04T01:03:19.000Z", "systemIds": [ "org.grails.plugins:gsp" ], "vcsUrl": "https://github.com/grails/grails-gsp" }, "documentationUrl": "https://gsp.grails.org/latest/guide/index.html", "mavenMetadataUrl": "https://repo1.maven.org/maven2/org/grails/plugins/gsp/maven-metadata.xml", "readme": "
\n
\n
\n

This project contains the sources for GSP, the server-side view rendering technology used in Grails.

\n
\n
\n
\n
\n

Documentation

\n
\n
\n\n
\n
\n
" }, { "bintrayPackage": { "name": "handlebars-asset-pipeline", "repo": "asset-pipeline", "owner": "bertramlabs", "desc": "Provides native Handlebars file support in the asset-pipeline. Easily convert .hbs or .handlebars files into javascript template caches for use with the handlebars runtime.", "labels": [ "asset-pipeline", "handlebars" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/bertramdev/asset-pipeline/issues", "latestVersion": "5.0.1", "updated": "2024-09-13T18:26:41.000Z", "systemIds": [ "com.bertramlabs.plugins:handlebars-asset-pipeline" ], "vcsUrl": "https://github.com/bertramdev/asset-pipeline" }, "documentationUrl": "https://bertramdev.github.io/asset-pipeline/", "mavenMetadataUrl": "https://repo1.maven.org/maven2/com/bertramlabs/plugins/handlebars-asset-pipeline/maven-metadata.xml", "readme": null }, { "bintrayPackage": { "name": "handlebars-renderer", "repo": "plugins", "owner": "salex772", "desc": "Grails handlebars templates renderer plugin", "labels": [ "handlebars" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/salex772/handlebars-renderer/issues", "latestVersion": "0.1.2", "updated": "2016-05-30T14:11:29.543Z", "systemIds": [ "org.grails.plugins:handlebars-renderer" ], "vcsUrl": "https://github.com/salex772/handlebars-renderer" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Grails handlebars templates renderer plugin

\n

This plugin is for Grails 3 and this is a fork of https://github.com/davidtinker/grails-handlebars

\n

Install

\n

Add to build.gradle

\n
dependencies {\n     compile "org.grails.plugins:handlebars-renderer:0.1.2"\n}\n
\n

Config

\n
grails.handlebars.templatesRoot = 'templates'\ngrails.handlebars.templateExtension = '.hbs'\ngrails.handlebars.templatesPathSeparator = '/'\n
\n

Usage

\n

In controller:

\n
def data = [\n\tname  : 'alex',\n]\n\n//income.hbs must under path /src/main/webapps/templates/mailbox\nrender handlebarsService.apply("mailbox/income", data)\n
\n

In GSP template:

\n
<handlebars:render template="mailbox/income" model="${data}"/>\n
\n

or

\n
<handlebars:render>\n    Hello {{name}} from the controller\n</handlebars:render>\n
\n

Please read complete documentation at https://github.com/davidtinker/grails-handlebars

\n" }, { "bintrayPackage": { "name": "hazelcast", "repo": "grails-plugins", "owner": "budjb", "desc": "Grails hazelcast plugin", "labels": [ "hazelcast" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/budjb/grails-hazelcast/issues", "latestVersion": "1.1.1", "updated": "2018-07-19T20:30:23.897Z", "systemIds": [ "org.grails.plugins:hazelcast" ], "vcsUrl": "https://github.com/budjb/grails-hazelcast" }, "documentationUrl": "https://budjb.github.io/grails-hazelcast/latest/", "mavenMetadataUrl": null, "readme": "

\"Build\n\"License\"

\n

Grails Hazelcast Plugin

\n

See the documentation at https://budjb.github.io/grails-hazelcast/latest.

\n" }, { "bintrayPackage": { "name": "hazelgrails", "repo": "plugins", "owner": "enesakar", "desc": "Hazelcast Grails Integration", "labels": [ "hazelcast" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/enesakar/hazelgrails/issues", "latestVersion": "1.0.2", "updated": "2016-04-18T13:39:17.430Z", "systemIds": [ "org.grails.plugins:hazelgrails" ], "vcsUrl": "https://github.com/enesakar/hazelgrails" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Hazelcast plugin for grails

\n

Update (4/2016): Hazelcast version is upgraded to 3.6.2.

\n

How to Install Plugin

\n

Just add the following dependency under the dependencies block in your project's build.gradle:

\n
\n

compile "org.grails.plugins:hazelgrails:1.0.2"

\n
\n

Configuration

\n

You can configure hazelcast in details:

\n

For available options have a look at:\nhttp://docs.hazelcast.org/docs/3.6/manual/html-single/index.html#hazelcast-configuration

\n

To use Hazelcast as Hibernate 2nd Level Cache, add the following line to application.groovy:

\n

cache.region.factory_class = 'com.hazelcast.hibernate.HazelcastCacheRegionFactory'

\n

For more documentation:

\n

See:\nhttp://blog.hazelcast.com/distribute-grails-with-hazelcast/

\n

For Grails3 Test application:

\n

See:\n[https://github.com/rohitbishnoi/hazelcast-test] (https://github.com/rohitbishnoi/hazelcast-test)

\n" }, { "bintrayPackage": { "name": "hibernate", "repo": "plugins", "owner": "grails", "desc": "GORM - Grails Data Access Framework", "labels": [ "database", "gorm", "hibernate", "rdms" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails/grails-data-mapping/issues", "latestVersion": "4.3.10.7", "updated": "2016-10-03T14:41:45.128Z", "systemIds": [ "org.grails.plugins:hibernate" ], "vcsUrl": "https://github.com/grails/grails-data-mapping" }, "documentationUrl": "https://grails.github.io/grails-data-mapping/", "mavenMetadataUrl": null, "readme": "

\"Java\n\"Release\"\n\"Maven

\n

GORM (Grails Object Mapping)

\n

[Grails][Grails] is a framework used to build web applications with the [Groovy][Groovy] programming language. This project provides the plumbings for the GORM API both for Hibernate and for new implementations of GORM ontop of NoSQL datastores.\n[Grails]: http://grails.org/\n[Groovy]: http://groovy-lang.org/

\n

Getting Started

\n

For further information see the dedicated websites:

\n\n

License

\n

Grails and Groovy are licensed under the terms of the [Apache License, Version 2.0][Apache License, Version 2.0].\n[Apache License, Version 2.0]: http://www.apache.org/licenses/LICENSE-2.0.html

\n" }, { "bintrayPackage": { "name": "hibernate-search", "repo": "plugins", "owner": "lgrignon", "desc": "This plugin aims to integrate Hibernate Search features to Grails in very few steps.", "labels": [ "search", "hibernate" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/mathpere/grails-hibernate-search-plugin/issues", "latestVersion": "2.4.0", "updated": "2020-04-10T16:57:56.220Z", "systemIds": [ "org.grails.plugins:hibernate-search" ], "vcsUrl": "https://github.com/mathpere/grails-hibernate-search-plugin" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Grails Hibernate Search Plugin

\n

This plugin aims to integrate Hibernate Search features to Grails in very few steps.

\n\n

Getting started

\n

If you don't want to start from the template project, you could start a fresh project:

\n

And add the following to your dependencies

\n
  compile("org.grails.plugins:hibernate-search:2.3.0")\n  compile("org.grails.plugins:hibernate5:6.1.8")\n  compile("org.grails.plugins:cache")\n  compile("org.hibernate:hibernate-core:5.2.10.Final")\n  compile("org.hibernate:hibernate-ehcache:5.2.10.Final")\n
\n

Configuration

\n

By default, the plugin stores your indexes in this directory:

\n
 ~/.grails/${grailsVersion}/projects/${yourProjectName}/lucene-index/development/\n
\n

You can override this configuration in your application.yml

\n
hibernate:\n    cache:\n        use_second_level_cache: true\n        use_query_cache: true\n        provider_class: net.sf.ehcache.hibernate.EhCacheProvider\n        region:\n            factory_class: org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory\n    search:\n        default:\n        \tindexBase: '/path/to/your/indexes'\n            indexmanager: near-real-time\n            directory_provider: filesystem\n
\n

You can also define the path to your indexes with JNDI configuration as following:

\n
hibernate:\n    cache:\n        use_second_level_cache: true\n        use_query_cache: true\n        provider_class: net.sf.ehcache.hibernate.EhCacheProvider\n        region:\n            factory_class: org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory\n    search:\n        default:\n            indexBaseJndiName: 'java:comp/env/luceneIndexBase'\n            directory_provider: filesystem\n
\n

Indexing

\n

Mark your domain classes as indexable

\n

Add a static lucenceIndexing closure as following:

\n

Note: You can use properties from super class and traits with no additional configuration (since 2.0.2)

\n
class MyDomainClass {\n\n    String author\n    String body\n    Date publishedDate\n    String summary\n    String title\n    Status status\n    Double price\n    Integer someInteger\n\n    enum Status {\n        DISABLED, PENDING, ENABLED\n    }\n\n    static hasMany = [categories: Category, items: Item]\n\n    static luceneIndexing = {\n        // fields\n        author index: 'yes'\n        body termVector: 'with_positions'\n        publishedDate date: 'day'\n        summary boost: 5.9\n        title index: 'yes', sortable: [name: title_sort, normalizer: LowerCaseFilterFactory]\n        status index: 'yes', sortable: true\n        categories indexEmbedded: true\n        items indexEmbedded: [depth: 2] // configure the depth indexing\n        price numeric: 2, analyze: false\n        someInteger index: 'yes', bridge: ['class': PaddedIntegerBridge, params: ['padding': 10]]\n\n        // support for classBridge\n        classBridge = ['class': MyClassBridge, params: [myParam: "4"]]\n    }\n\n}\n
\n

This static property indicates which fields should be indexed and describes how the field has to be indexed.

\n

Also, the plugin lets you to mark your domain classes as indexable with the Hibernate Search annotations.

\n
@Indexed\n@ClassBridge(\n     impl = MyClassBridge,\n     params = @Parameter( name="myParam", value="4" ) )\nclass MyDomainClass {\n\n    // when using annotations, id is required to define DocumentId\n    @DocumentId\n    Long id\n\n    @Field(index=Index.YES)\n    String author\n\n    @Field(index=Index.YES)\n    String body\n\n    @Field\n    @DateBridge(resolution=Resolution.DAY)\n    Date publishedDate\n\n    @Field(index=Index.YES)\n    String summary\n\n    @Field(index=Index.YES)\n    @Field(name="title_sort", normalizer=@Normalizer(impl=LowerCaseFilterFactory))\n    @SortableField(forField="title_sort")\n    String title\n\n    @Field(index=Index.YES)\n    @SortableField\n    Status status\n\n    @Field\n    @NumericField( precisionStep = 2)\n    Double price\n\n    @Field(index=Index.YES)\n    @FieldBridge(impl = PaddedIntegerBridge.class, params = @Parameter(name="padding", value="10"))\n    Integer someInteger\n\n    enum Status {\n        DISABLED, PENDING, ENABLED\n    }\n\n    @IndexedEmbedded\n    Set categories\n\n    @IndexedEmbedded(depth = 2)\n    Set items\n\n    static hasMany = [categories: Category, items: Item]\n\n}\n
\n

Indexing the data

\n

Create index for existing data

\n

The plugin lets you to create index of any indexed entity as following:

\n
MyDomainClass.search().createIndexAndWait()\n
\n

This method relies on MassIndexer and can be configured like this:

\n
\nMyDomainClass.search().createIndexAndWait {\n   ...\n   batchSizeToLoadObjects 25\n   cacheMode org.hibernate.CacheMode.NORMAL\n   threadsToLoadObjects 5\n   ...\n}\n\n#### Manual index changes\n\n##### Adding instances to index\n\n```groovy\n\n// index only updated at commit time\nMyDomainClass.search().withTransaction { transaction ->\n   MyDomainClass.findAll().each {\n      it.search().index()\n   }\n}\n
\n

Deleting instances from index

\n
\n// index only updated at commit time\nMyDomainClass.search().withTransaction { transaction ->\n\n   MyDomainClass.get(3).search().purge()\n\n}\n
\n

To remove all entities of a given type, you could use the following purgeAll method:

\n
\n// index only updated at commit time\nMyDomainClass.search().withTransaction {\n   MyDomainClass.search().purgeAll()\n}\n
\n

Rebuild index on start

\n

Hibernate Search offers an option to rebuild the whole index using the MassIndexer API. This plugin provides a configuration which lets you to rebuild automatically your indexes on startup.

\n

To use the default options of the MassIndexer API, simply provide this option into your runtime.groovy:

\n
\n\ngrails.plugins.hibernatesearch = {\n    rebuildIndexOnStart true\n}\n\n
\n

If you need to tune the MassIndexer API, you could specify options with a closure as following:

\n
\ngrails.plugins.hibernatesearch = {\n\n    rebuildIndexOnStart {\n\t\tbatchSizeToLoadObjects 30\n\t\tthreadsForSubsequentFetching 8 \t\n\t\tthreadsToLoadObjects 4\n\t\tthreadsForIndexWriter 3\n\t\tcacheMode CacheMode.NORMAL\n    }\n\n}\n\n
\n

Search

\n

The plugin provides you dynamic method to search for indexed entities.

\n

Retrieving the results

\n

All indexed domain classes provides .search() method which lets you to list the results.\nThe plugin provides a search DSL for simplifying the way you can search. Here is what it looks like with the search DSL:\n(See the HibernateSearchQueryBuilder class to check the available methods)

\n
class SomeController {\n\n   def myAction = { MyCommand command ->\n\n      def page = [max: Math.min(params.max ? params.int('max') : 10, 50), offset: params.offset ? params.int('offset') : 0]\n\n      def myDomainClasses = MyDomainClass.search().list {\n\n         if ( command.dateTo ) {\n            below "publishedDate", command.dateTo\n         }\n\n         if ( command.dateFrom ) {\n            above "publishedDate", command.dateFrom\n         }\n\n         mustNot {\n            keyword "status", Status.DISABLED\n         }\n\n         if ( command.keyword ) {\n            should {\n               command.keyword.tokenize().each { keyword ->\n\n                  def wild = keyword.toLowerCase() + '*'\n\n                  wildcard "author", wild\n                  wildcard "body", wild\n                  wildcard "summary", wild\n                  wildcard "title", wild\n                  wildcard "categories.name", wild\n               }\n            }\n         }\n\n         sort "publishedDate", "asc"\n\n         maxResults page.max\n\n         offset page.offset\n      }\n\n      [myDomainClasses: myDomainClasses]\n   }\n}\n
\n

Mixing with criteria query

\n

Criteria criteria = fullTextSession.createCriteria( clazz ).createAlias("session", "session").add(Restrictions.eq("session.id", 115L));

\n
  def myDomainClasses = MyDomainClass.search().list {\n\n    criteria {\n       setFetchMode("authors", FetchMode.JOIN)\n    }\n\n    fuzzy "description", "mi search"\n  }\n
\n

Performing SimpleQueryString searches

\n

See Hibernate Search Simple Query Strings for more details on the actual query string.\nYou can implement any other queries alongside a simple query string search.

\n

Simple search on 1 field

\n
// Search for "war and peace or harmony" in the title field\ndef myDomainClasses = MyDomainClass.search().list {\n\tsimpleQueryString 'war + (peace | harmony)', 'title'\n}\n
\n

Simple search on multiple fields

\n
// Search for "war and peace or harmony" in the title and description field\ndef myDomainClasses = MyDomainClass.search().list {\n\tsimpleQueryString 'war + (peace | harmony)', 'title', 'description\n}\n
\n

Simple search on field setting AND as the default operator

\n
// Search for "war and peace" in the title field\ndef myDomainClasses = MyDomainClass.search().list {\n\tsimpleQueryString 'war peace', [withAndAsDefaultOperator: true], 'title'\n}\n
\n

Simple search on multiple fields setting the boost for each field

\n
// Search for "war and peace" in the title field and description field with boosts applied\ndef myDomainClasses = MyDomainClass.search().list {\n\tsimpleQueryString 'war + (peace | harmony)', ['title':2.0, 'description':0.5]\n}\n
\n

Sorting the results

\n

sort() method accepts an optional second parameter to specify the sort order: "asc"/"desc". Default is "asc".

\n

Fields used for sorting can be analyzed, but must not be tokenized, so you should rather use normalizers on those fields.

\n

If you try to sort on an indexed field which has not been marked as "sortable" you will either get warnings or full errors.\nTherefore it is important to mark any indexed fields as sortable, and as sortable fields cannot be indexed with tokenizer analyzers you should also define a normalizer to be used (see the section on Normalizers on how to define them).

\n
MyDomainClass.search().list {\n   ...\n   sort "publishedDate", "asc"\n   ...  \n}\n
\n

If for some reasons, you want to sort results with a property which doesn't exist in your domain class, you should specify the sort type with a third parameter (default is String). You have three ways to achieve this:

\n

By Specifying the type (could be Integer, String, Date, Double, Float, Long, Bigdecimal):

\n
MyDomainClass.search().list {\n   ...\n   sort "my_special_field", "asc", Integer\n   ...\n}\n
\n

By Specifying directly its sort field (Lucene):

\n
def items = Item.search().list {\n  ...\n  sort "my_special_field", "asc", org.apache.lucene.search.SortField.Type.STRING_VAL\n  ...\n}\n
\n

By specifying its sort field with string:

\n
def items = Item.search().list {\n  ...\n  sort "my_special_field", "asc", "string_val"\n  ...\n}\n
\n

Counting the results

\n

You can also retrieve the number of results by using 'count' method:

\n
def myDomainClasses = MyDomainClass.search().count {\n ...\n}\n
\n

Additional features

\n

Support for ignoreAnalyzer(), ignoreFieldBridge() and boostedTo() functions

\n

When searching for data, you may want to not use the field bridge or the analyzer. All methods (below, above, between, keyword, fuzzy) accept an optional map parameter to support this:

\n
\nMyDomainClass.search().list {\n\n   keyword "status", Status.DISABLED, [ignoreAnalyzer: true]\n\n   wildcard "description", "hellow*", [ignoreFieldBridge: true, boostedTo: 1.5f]\n\n}\n
\n

Fuzzy search

\n

On fuzzy search, you can add an optional parameter to specify the max distance

\n

See Hibernate Fuzzy Search

\n
\nMyDomainClass.search().list {\n\n   keyword "status", Status.DISABLED, [ignoreAnalyzer: true]\n\n   fuzzy "description", "hellow", [ignoreFieldBridge: true, maxDistance: 2]\n\n}\n
\n

Support for projections

\n

Hibernate Search lets you to return only a subset of properties rather than the whole domain object. It makes it possible to avoid to query the database. This plugin supports this feature:

\n
def myDomainClasses = MyDomainClass.search().list {\n\n    projection "author", "body"\n\n}\n\nmyDomainClasses.each { result ->\n\n    def author = result[0]\n    def body  = result[1]\n\n    ...\n}\n\n
\n

Don't forget to store the properties into the index as following:

\n
class MyDomainClass {\n\n    [...]\n\n    static luceneIndexing = {\n        author index: 'yes', store: 'yes'\n        body index: 'yes', store: 'yes'\n    }\n}\n
\n

Analysis

\n

Define named analyzers

\n

Named analyzers are global and can be defined within runtime.groovy as following:

\n
\nimport org.apache.solr.analysis.StandardTokenizerFactory\nimport org.apache.solr.analysis.LowerCaseFilterFactory\nimport org.apache.solr.analysis.NGramFilterFactory\n\n...\n\ngrails.plugins.hibernatesearch = {\n\n    analyzer( name: 'ngram', tokenizer: StandardTokenizerFactory ) {\n        filter LowerCaseFilterFactory\n        filter factory: NGramFilterFactory, params: [minGramSize: 3, maxGramSize: 3]\n    }\n\n}\n\n
\n

This configuration is strictly equivalent to this annotation configuration:

\n
@AnalyzerDef(name = "ngram", tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),\n  filters = {\n    @TokenFilterDef(factory = LowerCaseFilterFactory.class),\n    @TokenFilterDef(factory = NGramFilterFactory.class,\n      params = {\n        @Parameter(name = "minGramSize",value = "3"),\n        @Parameter(name = "maxGramSize",value = "3")\n     })\n})\npublic class Address {\n...\n}\n
\n

Use named analyzers

\n

Set the analyzer at the entity level: all fields will be indexed with the analyzer

\n
class MyDomainClass {\n\n    String author\n    String body\n    ...\n\n    static luceneIndexing = {\n        analyzer = 'ngram'\n        author index: 'yes'\n        body index: 'yes'\n    }\n\n}\n
\n

Or set the analyzer at the field level:

\n
class MyDomainClass {\n\n    String author\n    String body\n    ...\n\n    static luceneIndexing = {\n        author index: 'yes'\n        body index: 'yes', analyzer: 'ngram'\n        other index: 'yes', analyzer: new MyFilter()\n    }\n\n}\n
\n

Get scoped analyzer for given entity

\n

The plugin lets you ro retrieve the scoped analyzer for a given analyzer with the search() method:

\n
def parser = new org.apache.lucene.queryParser.QueryParser (\n    "title", Song.search().getAnalyzer() )\n
\n

Normalizer

\n

Normalizers are analyzers without tokenization and are important for indexed fields which you want to sort,\nsee Hibernate Search Normalizer for more information.

\n

Define named normalizers

\n

Named normalizers are global and can be defined within runtime.groovy as following:

\n
\nimport org.apache.lucene.analysis.core.LowerCaseFilterFactory\nimport org.apache.lucene.analysis.miscellaneous.ASCIIFoldingFilterFactory\n\n...\n\ngrails.plugins.hibernatesearch = {\n\n    normalizer(name: 'lowercase') {\n        filter ASCIIFoldingFilterFactory\n        filter LowerCaseFilterFactory\n    }\n\n}\n\n
\n

This configuration is strictly equivalent to this annotation configuration:

\n
@NormalizerDef(name = "lowercase",\n  filters = {\n    @TokenFilterDef(factory = ASCIIFoldingFilterFactory.class),\n    @TokenFilterDef(factory = LowerCaseFilterFactory.class)\n})\npublic class Address {\n...\n}\n
\n

Use named normalizer

\n

Set the normalizer at the field level

\n
class MyDomainClass {\n\n    String author\n    String body\n    ...\n\n    static luceneIndexing = {\n        author index: 'yes', sortable: [name: author_sort, normalizer: 'lowercase']\n        body index: 'yes', sortable: [name: author_sort, normalizer: LowerCaseFilterFactory]\n    }\n\n}\n
\n

Filters

\n

In Hibernate Search 5.9.x the Filter class is completely removed and filters must now be applied as\nFull-Text Filters\nwhich are passed Querys rather than Filters.

\n

Define named filters

\n

Named filters are global and MUST be defined within runtime.groovy as following:

\n
\n...\n\ngrails.plugins.hibernatesearch = {\n\n    // cf official doc https://docs.jboss.org/hibernate/stable/search/reference/en-US/html_single/#query-filter-fulltext\n    // Example 116. Defining and implementing a Filter\n    fullTextFilter name: "bestDriver", impl: BestDriversFilter\n\n    // cf official doc https://docs.jboss.org/hibernate/stable/search/reference/en-US/html_single/#query-filter-fulltext\n    // Example 118. Using parameters in the actual filter implementation    \n    fullTextFilter name: "security", impl: SecurityFilterFactory, cache: "instance_only"\n\n}\n\n
\n

If they are not defined in runtime.groovy they will not be available for querying.

\n

Filter query results

\n

Filter query results looks like this:

\n

MyDomainClass.search().list {

\n
\n// without params:\nMyDomainClass.search().list {\n  ...\n  filter "bestDriver"\n  ...\n}\n\n// with params:\nMyDomainClass.search().list {\n  ...\n   filter name: "security", params: [ level: 4 ]\n  ...\n}\n\n
\n

Options

\n
grails.plugins.hibernatesearch = {\n\trebuildIndexOnStart false // see related section above\n\tthrowOnEmptyQuery false // throw or not exception when Hibernate Search raises an EmptyQueryException\n\tfullTextFilter /* ... */ // see related section above\n}\n
\n

Notes

\n

Updating from 2.2 to 2.3

\n

There is a signification change between 2.2 and 2.3.

\n

Updating filters

\n

Filters must now be defined in the runtime.groovy in advance and then added to a query as filter definitions which will define fullTextFilters.\nThis is due to the deprecation of the filter class from Hibernate Search.

\n

runtime.groovy vs application.groovy

\n

In Grails 3 the application.groovy file is loaded when the Grails CLI is started,\ntherefore certain logic and requirements on dependencies will fall over when defined in the application.groovy file.

\n

The solution is to define a runtime.groovy file and move the logic into this file,\nthis also helps to provide a nice divide on what logic is required when running the application\nand as config is now provided in the application.yml file it should result in only needing to define a runtime.groovy file and not the\napplication.groovy file.

\n

We therefore advise all hibernatesearch closure config to be defined in the runtime.groovy file.

\n

runtime.groovy is run along with application.groovy when the application starts up, it is also packaged and run by a WAR.

\n

IDE Integration

\n

Unfortunately IDEs will not recognise the search() method as it is added dynamically.\nOne messy but possible way to get around this and gain access to the DSL inside the IDE is to\nadd an extra static method to your class.\nThis is not ideal but it may make your programming easier.

\n
class DomainClass {\n\n    ...\n\n    static List<DomainClass> hibernateSearchList(@DelegatesTo(HibernateSearchApi) Closure closure){\n        DomainClass.search().list(closure)\n    }\n    \n    static int hibernateSearchCount(@DelegatesTo(HibernateSearchApi) Closure closure){\n        DomainClass.search().count(closure)\n    }\n}\n
\n

SessionFactory failures during startup

\n

During the SessionFactory build process any exceptions which occur during the HibernateSearch boot sequence\nare silently wrapped and hidden inside the futures.\nThis means there will be a particularly helpful exception thrown :

\n
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'methodValidationPostProcessor' defined in class path resource [org/springframework/boot/autoconfigure/validation/ValidationAutoConfiguration.class]: Unsatisfied dependency expressed through method 'methodValidationPostProcessor' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'hibernateDatastoreServiceRegistry': Cannot resolve reference to bean 'hibernateDatastore' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'hibernateDatastore': Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.grails.orm.hibernate.HibernateDatastore]: Constructor threw exception; nested exception is java.lang.NullPointerException\n
\n

which will stacktrace down to :

\n
Caused by: java.lang.NullPointerException: null\n\tat org.grails.orm.hibernate.cfg.HibernateMappingContextConfiguration$2.sessionFactoryClosed(HibernateMappingContextConfiguration.java:266)\n\tat org.hibernate.internal.SessionFactoryObserverChain.sessionFactoryClosed(SessionFactoryObserverChain.java:61)\n\tat org.hibernate.internal.SessionFactoryImpl.close(SessionFactoryImpl.java:756)\n\tat org.hibernate.search.hcore.impl.HibernateSearchSessionFactoryObserver.boot(HibernateSearchSessionFactoryObserver.java:134)\n\tat org.hibernate.search.hcore.impl.HibernateSearchSessionFactoryObserver.sessionFactoryCreated(HibernateSearchSessionFactoryObserver.java:79)\n\tat org.hibernate.internal.SessionFactoryObserverChain.sessionFactoryCreated(SessionFactoryObserverChain.java:35)\n\tat org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:366)\n\tat org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:452)\n\tat org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:710)\n\tat org.grails.orm.hibernate.cfg.HibernateMappingContextConfiguration.buildSessionFactory(HibernateMappingContextConfiguration.java:274)\n\tat grails.plugins.hibernate.search.context.HibernateSearchMappingContextConfiguration.buildSessionFactory(HibernateSearchMappingContextConfiguration.java:357)\n\tat org.grails.orm.hibernate.connections.HibernateConnectionSourceFactory.create(HibernateConnectionSourceFactory.java:86)\n\tat org.grails.orm.hibernate.connections.AbstractHibernateConnectionSourceFactory.create(AbstractHibernateConnectionSourceFactory.java:39)\n\tat org.grails.orm.hibernate.connections.AbstractHibernateConnectionSourceFactory.create(AbstractHibernateConnectionSourceFactory.java:23)\n\tat org.grails.datastore.mapping.core.connections.AbstractConnectionSourceFactory.create(AbstractConnectionSourceFactory.java:64)\n\tat org.grails.datastore.mapping.core.connections.AbstractConnectionSourceFactory.create(AbstractConnectionSourceFactory.java:52)\n\tat org.grails.datastore.mapping.core.connections.ConnectionSourcesInitializer.create(ConnectionSourcesInitializer.groovy:24)\n\tat org.grails.orm.hibernate.HibernateDatastore.<init>(HibernateDatastore.java:196)\n\tat sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)\n\tat sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)\n\tat sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)\n\tat java.lang.reflect.Constructor.newInstance(Constructor.java:423)\n\tat org.springsource.loaded.ri.ReflectiveInterceptor.jlrConstructorNewInstance(ReflectiveInterceptor.java:1076)\n\tat org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:142)\n\t... 51 common frames omitted\n
\n

The actual exception stack is not at all helpful as whilst the actual failure point is in:

\n
org.hibernate.search.hcore.impl.HibernateSearchSessionFactoryObserver.boot(HibernateSearchSessionFactoryObserver.java:134)\n
\n

It is masked inside the catch statement at line 127 inside the class,\nas the finally clause is what results in the above exception stacktrace.

\n
public class HibernateSearchSessionFactoryObserver implements SessionFactoryObserver {\n    // ...\n    \n    private synchronized void boot(SessionFactory factory) {\n        try{ \n            // ...\n        }\n        catch (Throwable t) {\n            extendedSearchIntegratorFuture.completeExceptionally( t );\n            // This will make the SessionFactory abort and close itself\n            throw t;\n        }finally {\n            if ( failedBoot ) {\n                factory.close();\n            }\n        }\n    }\n    \n    // ...\n}\n
\n

Therefore if you get the above exceptions then drop a debug point at line 130 and then start with a debugger running.\nThe debug point will give you the helpful exception as to why the boot has failed.

\n

Examples

\n

A sample project is available at this repository URL\nhttps://github.com/lgrignon/grails3-quick-start

\n

It contains several branches for each version of this plugin

\n

Change log

\n

v2.3

\n\n

v2.2

\n\n

v2.1.2

\n\n

v2.1

\n\n

v2.0.2

\n

Support for indexing trait properties

\n

v2.0.1

\n

Support for indexing inherited properties

\n

v2.0

\n\n

v1.x

\n\n

Authors

\n

Mathieu Perez

\n\n

Julie Ingignoli

\n\n

Louis Grignon

\n\n

Development / Contribution

\n

Install with:

\n
gradlew clean publishToMavenLocal\n
\n

Publish with:

\n
gradlew clean bintrayUpload --stacktrace -PbintrayUser=... -PbintrayKey=...\n
\n

License

\n

Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0

\n" }, { "bintrayPackage": { "name": "hibernate3", "repo": "plugins", "owner": "grails", "desc": "GORM - Grails Data Access Framework", "labels": [ "database", "gorm", "hibernate", "rdms" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails/grails-data-mapping/issues", "latestVersion": "5.0.13", "updated": "2017-03-21T12:02:19.359Z", "systemIds": [ "org.grails.plugins:hibernate3" ], "vcsUrl": "https://github.com/grails/grails-data-mapping" }, "documentationUrl": "https://grails.github.io/grails-data-mapping/", "mavenMetadataUrl": null, "readme": "

\"Java\n\"Release\"\n\"Maven

\n

GORM (Grails Object Mapping)

\n

[Grails][Grails] is a framework used to build web applications with the [Groovy][Groovy] programming language. This project provides the plumbings for the GORM API both for Hibernate and for new implementations of GORM ontop of NoSQL datastores.\n[Grails]: http://grails.org/\n[Groovy]: http://groovy-lang.org/

\n

Getting Started

\n

For further information see the dedicated websites:

\n\n

License

\n

Grails and Groovy are licensed under the terms of the [Apache License, Version 2.0][Apache License, Version 2.0].\n[Apache License, Version 2.0]: http://www.apache.org/licenses/LICENSE-2.0.html

\n" }, { "bintrayPackage": { "name": "hibernate4", "repo": "plugins", "owner": "grails", "desc": "GORM - Grails Data Access Framework", "labels": [ "database", "gorm", "hibernate", "rdms" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails/gorm-hibernate4", "latestVersion": "6.1.8", "updated": "2017-10-27T06:58:00.000Z", "systemIds": [ "org.grails.plugins:hibernate4" ], "vcsUrl": "https://github.com/grails/gorm-hibernate4" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

GORM for Hibernate 4

\n

This project implements GORM for the Hibernate 4.

\n

For more information see the following links:

\n\n

For the current development version see the following links:

\n\n" }, { "bintrayPackage": { "name": "hibernate5", "repo": "plugins", "owner": "grails", "desc": "GORM - Grails Data Access Framework", "labels": [ "database", "gorm", "hibernate", "rdms" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails/grails-data-mapping/issues", "latestVersion": "8.1.0", "updated": "2024-03-15T13:00:05.000Z", "systemIds": [ "org.grails.plugins:hibernate5" ], "vcsUrl": "https://github.com/grails/grails-data-mapping" }, "documentationUrl": "https://grails.github.io/grails-data-mapping/", "mavenMetadataUrl": "https://repo1.maven.org/maven2/org/grails/plugins/hibernate5/maven-metadata.xml", "readme": "

\"Java\n\"Release\"\n\"Maven

\n

GORM (Grails Object Mapping)

\n

[Grails][Grails] is a framework used to build web applications with the [Groovy][Groovy] programming language. This project provides the plumbings for the GORM API both for Hibernate and for new implementations of GORM ontop of NoSQL datastores.\n[Grails]: http://grails.org/\n[Groovy]: http://groovy-lang.org/

\n

Getting Started

\n

For further information see the dedicated websites:

\n\n

License

\n

Grails and Groovy are licensed under the terms of the [Apache License, Version 2.0][Apache License, Version 2.0].\n[Apache License, Version 2.0]: http://www.apache.org/licenses/LICENSE-2.0.html

\n" }, { "bintrayPackage": { "name": "html-cleaner", "repo": "grails-plugins", "owner": "snimavat", "desc": "Html Cleaner Grails Plugin", "labels": [ "html" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/snimavat/html-cleaner/issues", "latestVersion": "3.0.0.1", "updated": "2017-01-16T10:18:16.040Z", "systemIds": [ "org.grails.plugins:html-cleaner" ], "vcsUrl": "https://github.com/snimavat/html-cleaner" }, "documentationUrl": "https://snimavat.github.io/html-cleaner/", "mavenMetadataUrl": null, "readme": "

\"Build

\n

See documentation

\n" }, { "deprecated": "Source repository is archived and this is a duplicate of a plugin with the same name by snimavat. This entry in the registry should probably be removed to avoid confusion.", "bintrayPackage": { "name": "html-cleaner", "repo": "plugins", "owner": "agorapulse", "desc": "Grails HTML Cleaner plugin", "labels": [ "html" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/agorapulse/grails-html-cleaner/issues", "latestVersion": "1.1", "updated": "2016-05-03T11:57:38.051Z", "systemIds": [ "org.grails.plugins:html-cleaner" ], "vcsUrl": "https://github.com/agorapulse/grails-html-cleaner" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Html Cleaner Grails Plugin

\n

\"Build\n\"Download\"

\n

Introduction

\n

The Html Cleaner Plugin is a whitelist based html sanitizer, based on Jsoup.\nThis is a port to Grails3 of the Grails1 plugin, originally written by Sudhir Nimavat.

\n

It provides:

\n\n

Note: Html cleaner is not just a sanitizer, it cleans ill-formed user supplied html and produces a well formed xml.

\n

Installation

\n

Declare the plugin dependency in the build.gradle file, as shown here:

\n
repositories {\n    ...\n    maven { url "http://dl.bintray.com/agorapulse/plugins" }\n}\ndependencies {\n    ...\n    compile "org.grails.plugins:html-cleaner:1.1"\n}\n
\n

Config

\n

Following whitelists are available by default and does not need any configuration:

\n\n

You can define default white list in your grails-app/conf/application.yml:

\n
grails:\n    plugin:\n        htmlcleaner:\n            defaultWhiteList: basic\n
\n

See below to define custom whitelists.

\n

Usage

\n

Let's say you have a form with a text area, but you don't want to allow any html. You can clean the user supplied text with whitelist none and it will stripe out all the html.

\n
import grails.plugin.htmlcleaner.HtmlCleaner\n\nclass FooController {\n\n    HtmlCleaner htmlCleaner\n\n    def save = {\n       String cleaned = htmlCleaner.cleanHtml(params.textArea, 'none') \n   }\n}\n
\n

Or in a service:

\n
import grails.plugin.htmlcleaner.HtmlCleaner\n\nclass FooService {\n\n    HtmlCleaner htmlCleaner\n\n    def foo(unsafe) {\n        String cleaned = htmlCleaner.cleanHtml(unsafe, 'none')\n    }\n}\n
\n

You can also allow basic html as per basic whitelist.

\n
def cleaned = htmlCleaner.cleanHtml(unsafe, 'basic')\n
\n

The plugin also provides a taglib.

\n
<hc:cleanHtml html="${domainInstance.description}" whitelist="basic"/>\n
\n

Defining custom whitelists

\n

Plugin provides a DSL to define custom whitelists in configuration.\nDefine a custom whitelist sample that will allow just b, i, p and span tags.

\n

application.groovy

\n
grails {\n    plugin {\n        htmlcleaner {\n            whitelists = {\n                whitelist("sample") {\n                    startwith "none"\n                    allow "b", "p", "i", "span"\n                }\n            }\n        }\n    }\n}\n
\n

The above configuration would define a whitelist with name sample that builds on top of whitelist none and allows additional tags b, i, p and span.

\n

A whitelist can start with any of the default whitelists or A whitelist can start with any custom whitelists that are defined earlier in configuration as well, but it must start with another whitelist.

\n

Define a whitelist sample2 that starts with whitelist sample we defined above and allows tag a with just one attribute href and puts rel="nofollow"

\n
grails {\n    plugin {\n        htmlcleaner {\n            whitelists = {\n                whitelist("sample2") {\n                    startwith "sample"\n                    allow("a") {\n                        attributes "href"\n                        enforce attribute:"rel", value:"nofollow"\n                    }\n                }\n            }\n        }\n    }\n}\n
\n

Define a whitelist basic-with-tables that starts with whitelist basic and allows tables.

\n
grails {\n    plugin {\n        htmlcleaner {\n            whitelists = {\n                whitelist("basic-with-tables") {\n                    startwith "basic"\n                    allow "table", "tr", "td"\n                }\n            }\n        }\n    }\n}\n
\n

Restricting attributes

\n
grails {\n    plugin {\n        htmlcleaner {\n            whitelists = {\n                whitelist("sample") {\n                    allow("div") {\n                        attributes "id", "class"\n                    }\n                }\n            }\n        }\n    }\n}\n
\n

Enforcing attributes - An enforced attribute will always be added to the element. If the element already has the attribute set, it will be overridden.

\n
grails {\n    plugin {\n        htmlcleaner {\n            whitelists = {\n                whitelist("sample") {\n                    allow("div") {\n                        enforce attribute:"class", value:"block"\n                    }\n                }\n            }\n        }\n    }\n}\n
\n

Defining multiple whitelists

\n
grails {\n    plugin {\n        htmlcleaner {\n            whitelists = {\n                whitelist("sample") {\n                    startwith "none"\n                    allow "b", "p", "span"\n                }\n                whitelist("sample-with-anchor") {\n                    startwith "sample"\n                    allow("a") {\n                        attributes "href"\n                        enforce attribute:"rel", value:"nofollow"\n                    }\n                }\n        \n                whitelist("basic-with-tables") {\n                    startwith "basic"\n                    allow "table", "tr", "td"\n                }\n        \n            }\n        }\n    }\n}\n
\n

Bugs

\n

To report any bug, please use the project Issues section on GitHub.

\n" }, { "bintrayPackage": { "name": "http-builder-helper", "repo": "plugins", "owner": "grails", "desc": "Grails HTTP Builder Helper Plugin", "labels": [ "http-client" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/bobbywarner/grails-http-builder-helper/issues", "latestVersion": "1.1.0", "updated": "2017-09-01T14:14:12.890Z", "systemIds": [ "org.grails.plugins:http-builder-helper" ], "vcsUrl": "https://github.com/bobbywarner/grails-http-builder-helper" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Grails HTTP Builder Helper

\n

This plugin used to be called the REST plugin in Grails 1.x & 2.x, but for Grails 3.x it has been renamed to httpbuilder-helper. The plugin enables the usage of HTTPBuilder in a Grails application.

\n

Description

\n

The REST plugin enables the usage of HTTPBuilder on a Grails application.

\n

Usage

\n

The plugins will inject the following dynamic methods:

\n\n

Examples

\n

Taken from HttpBuilder's Simplified GET Request

\n
withHttp(uri: "http://www.google.com") {\n   def html = get(path : '/search', query : [q:'Groovy'])\n   assert html.HEAD.size() == 1\n   assert html.BODY.size() == 1\n}\n
\n

Notice that you can call HTTPBuilder's methods inside stmts, the current HTTPBuilder is set as the closure's delegate. The same holds true for the other dynamic methods.\nAsyncHTTPBuilder

\n
import static groovyx.net.http.ContentType.HTML\nwithAsyncHttp(poolSize : 4, uri : "http://hc.apache.org", contentType : HTML) {\n   def result = get(path:'/') { resp, html ->\n      println ' got async response!'\n      return html\n   }\n   assert result instanceof java.util.concurrent.Future\n\n   while (! result.done) {\n      println 'waiting...'\n      Thread.sleep(2000)\n   }\n\n   /* The Future instance contains whatever is returned from the response\n      closure above; in this case the parsed HTML data: */\n   def html = result.get()\n   assert html instanceof groovy.util.slurpersupport.GPathResult\n}\n
\n

All dynamic methods will create a new http client when invoked unless you define an id: attribute. When this attribute is supplied the client will be stored as a property on the instance's metaClass. You will be able to access it via regular property access or using the id: again.

\n
class FooController {\n  def loginAction = {\n    withRest(id: "twitter", uri: "http://twitter.com/statuses/") {\n      auth.basic model.username, model.password\n    }\n  }\n  def queryAction = {\n    withRest(id: "twitter") {\n       def response = get(path: "followers.json")\n       // \ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\n    }\n    /* alternatively\n      def response twitter.get(path: "followers.json")\n    */\n  }\n}\n
\n

Configuration

\n

Dynamic method injection

\n

Dynamic methods will be added to controllers and services by default. You can change this setting by adding a configuration flag application.yml or application.groovy:

\n
grails.rest.injectInto = ["Controller", "Service", "Routes"]\n
\n

Proxy settings

\n

You can apply proxy settings by calling setProxy(String host, int port, String scheme) on the client/builders at any time. You can also take advantage of the proxy: shortcut

\n
withHttp(uri: "http://google.com", proxy: [host: "myproxy.acme.com", port: 8080, scheme: "http"])\n
\n

This shortcut has the following defaults

\n
port: = 80\nscheme: = http\n
\n

Meaning most of the times you'd only need to define a value for host:

\n

SSL Key-Store and Trust-Store support

\n

If you are connecting to a server through HTTPS you might need to add a Key and or a Trust Store to the underlying SSL Socket Factory. Some examples are\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd

\n

The service you are connecting to requires some sort of SSL Cert authentication,\nYou want to make sure that the server you are connecting to provides a specific certificate.\nYou do not mind that the certificate that the server provides doesn't match the Domain Name that the server has.\nNote, this last option will normally apply to development and test environments.

\n

So how can I add the Key and/or Trust Stores to the underlying SSL Socket Factory?

\n

The client will try to add a Key and a Trust Store if the URL of the host starts with https. By default it will attempt to locate a Key Store through the File System's path $HOME/.keystore e.g /home/berngp/.keystore and a Trust Store through the JVM Classpath ./truststore.jks, you can override this by specifying a rest.https.keystore.path and/or rest.https.truststore.path configuration entries in the application.yml or application.groovy file.

\n

Also by default it will try to open the stores using the following passwords '', 'changeit', 'changeme' but you can set a specific password through the rest.https.keystore.pass and rest.https.truststore.pass configuration entries. If for some reason it is unable to setup the underlying SSL Socket Factory it will fail silently unless the rest.https.sslSocketFactory.enforce configuration entry is set to true.

\n

Specifying a Hostname Verification strategy for the Trust Store.

\n

You can set three different Hostname Verification strategies through the rest.https.cert.hostnameVerifier configuration entry.

\n

ALLOW_ALL: The URL requested doesn't need to match the URL in the Certificate.\nSTRICT: The URL requested needs to match the URL in the Certificate.\nBROWSER_COMPATIBLE: The URL requested must be in the same domain as the one in the Certificate. It accepts wildcards.\nExample of a specific setup

\n
/** SSL truststore configuration key */\nrest.https.truststore.path = 'resources/certs/truststore.jks'\n/** SSL keystore configuration key */\nrest.https.keystore.path='resources/certs/keystore.jks'\n/** SSL keystore password configuration key */\nrest.https.keystore.pass='changeme'\n/** Certificate Hostname Verifier configuration key */\nrest.https.cert.hostnameVerifier = 'BROWSER_COMPATIBLE'\n/** Enforce SSL Socket Factory */\nrest.https.sslSocketFactory.enforce = true\n
\n

Generating a Key Store

\n

Generating a Java Key Store is outside the scope of this guide but you can find some useful information through the following links.

\n\n" }, { "bintrayPackage": { "name": "http-requests-grails", "repo": "maven", "owner": "budjb", "desc": "The HTTP Requests Plugin provides the http-requests library and artefacts for filters and converters.", "labels": [ "http-client" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/budjb/http-requests/issues", "latestVersion": "1.0.2", "updated": "2018-07-25T04:16:25.412Z", "systemIds": [ "com.budjb:http-requests-grails" ], "vcsUrl": "https://github.com/budjb/http-requests" }, "documentationUrl": "https://budjb.github.io/http-requests/", "mavenMetadataUrl": null, "readme": "

\"Build\n\"License\"

\n

HTTP Requests Library

\n

See the documentation at https://budjb.github.io/http-requests/latest.

\n" }, { "bintrayPackage": { "name": "i18n-asset-pipeline", "repo": "plugins", "owner": "amc-world", "desc": "asset-pipeline plugin to use localized messages in JavaScript.", "labels": [ "i18n", "javascript" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/dellermann/i18n-asset-pipeline/issues", "latestVersion": "2.0.0", "updated": "2016-03-31T13:31:54.872Z", "systemIds": [ "org.grails.plugins:i18n-asset-pipeline" ], "vcsUrl": "https://github.com/dellermann/i18n-asset-pipeline" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

I18n asset-pipeline plugin

\n

The Grails plugin i18n-asset-pipeline is an asset-pipeline plugin that\ngenerates a JavaScript file with localized texts which can be used for\nclient-side i18n.

\n

For more information on how to use asset-pipeline, visit\nasset-pipeline project page.

\n

Version information

\n

Because asset-pipeline 2.x and 3.x introduced new APIs and aren't backward\ncompatible, you must use the following versions of this plugin:

\n

i18n-asset-pipeline version | required for\n----------------------------|--------------\n0.x | asset-pipeline up to version 1.9.9\n1.x | asset-pipeline version 2.0.0 or higher\n2.x | Grails 3.x

\n

Installation

\n

To use this plugin you have to add the following code to your build.gradle:

\n
buildscript {\n    dependencies {\n        classpath 'org.amcworld.plugins:i18n-asset-pipeline:2.0.0'\n    }\n}\n\ndependencies {\n    runtime 'org.grails.plugins:i18n-asset-pipeline:2.0.0'\n}\n
\n

The first dependency declaration is needed to precompile your assets (e. g.\nwhen building a WAR file). The second one provides the necessary\n<asset:i18n> tag and compiles the assets on the fly (e. g. in development)\nmode.

\n

Usage

\n

i18n-asset-pipeline uses special files in your asset folders (we recommend\ngrails-app/assets/i18n) with extension '.i18n'. The names of\nthese files must contain a language specification separated by underscore, e.\ng. messages_de.i18n or messages_en_UK.i18n. Files without a language\nspecification (e. g. messages.i18n) are files for the default locale. These\nfiles mainly contain message codes that are resolved to localized texts.

\n

The plugin generates a JavaScript file, that contains a function named $L\nwhich can be called to obtain the localized message by a given code, e. g.:

\n
$(".btn").text($L("default.btn.ok"));\n
\n

I18n file syntax

\n

Each i18n file must be defined according to the following rules:

\n\n

Each i18n file may contain asset-pipeline require statements to load other\nassets such as JavaScript files. ATTENTION! Don't use require to load\nother i18n files because they will not be processed correctly. Use the\n@import declaration instead.

\n

Typical file structure

\n

Typically, you have one i18n file for each language in the application. Given,\nyou have the following message resources in grails-app/i18n:

\n\n

Then, you should have the same set of files in e. g. grails-app/assets/i18n:

\n\n

Normally, you would have to declare the same set of message codes in each file.\nTo DRY, add a file _messages.i18n to grails-app/assets/i18n (the\nleading underscore prevents the i18n file to be compiled itself):

\n
#\n# _messages.i18n\n# List of message codes that should be available on client-side.\n#\n\n# Add your messages codes here:\ndefault.btn.cancel\ndefault.btn.ok\ncontact.foo.bar\n\n
\n

Then, you can import this file in all other files, e. g.:

\n
#\n# messages.i18n\n# Client-side i18n, English messages.\n#\n\n@import _messages\n\n
\n
#\n# messages_de.i18n\n# Client-side i18n, German messages.\n#\n\n@import _messages\n\n
\n
#\n# messages_es.i18n\n# Client-side i18n, Spanish messages.\n#\n\n@import _messages\n\n
\n

Including localized assets

\n

In order to include a localized asset you can either use an asset-pipeline\nrequire directive or the tag <asset:i18n>. The tag supports the following\nattributes:

\n\n

Examples:

\n
<asset:i18n locale="en_UK" />\n
\n
<asset:i18n name="texts" locale="${locale}" />\n
\n

Author

\n

This plugin was written by Daniel Ellermann\n(AMC World Technologies GmbH).

\n

License

\n

This plugin was published under the\nApache License, Version 2.0.

\n" }, { "bintrayPackage": { "name": "i18n-enums", "repo": "plugins", "owner": "sbglasius", "desc": "This plugin adds an annotation usable on Enums to easy add and implement the MessageSourceResolvable interface in an standard way throughout a project.", "labels": [ "enums", "i18n" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/sbglasius/i18n-enums/issues", "latestVersion": "5.0.0", "updated": "2023-12-29T12:00:00.000Z", "systemIds": [ "org.grails.plugins:i18n-enums" ], "vcsUrl": "https://github.com/sbglasius/i18n-enums" }, "documentationUrl": "https://sbglasius.github.io/i18n-enums/", "mavenMetadataUrl": "https://repo1.maven.org/maven2/dk/glasius/i18n-enums/maven-metadata.xml", "readme": "

i18n-enums

\n

Documentation can be found here: http://sbglasius.github.io/i18n-enums/

\n" }, { "bintrayPackage": { "name": "i18n-javascript", "repo": "plugins", "owner": "salex772", "desc": "Render all Grails i18n messages to Javascript", "labels": [ "i18n", "javascript" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/salex772/i18n-javascript/issues", "latestVersion": "0.4.2", "updated": "2016-05-26T08:34:01.691Z", "systemIds": [ "org.grails.plugins:i18n-javascript" ], "vcsUrl": "https://github.com/salex772/i18n-javascript" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Render all Grails i18n messages to Javascript

\n

This plugin includes

\n\n

Install

\n

Add to build.gradle

\n
dependencies {\n     compile "org.grails.plugins:i18n-javascript:0.4.2"\n}\n
\n

Config

\n

In application.groovy add config with desired including and excluding prefixes

\n
i18nJs {\n    prefixInclude = [\n        'i18nJs'\n    ]\n\n    prefixExclude = [\n        'default', 'other'\n    ]\n}\n
\n

So 'i18nJs.page1.header' will be rendered whereas 'default.home.label' will not.\nWithout this all items from message.properties wiil be in JS

\n

Get messages

\n

In GSP use

\n
<g:i18nJs/>\n
\n

to render all messages in output HTML

\n

Or make request to /I18nJs/getMessages within AJAX call.

\n

Usage

\n
alert(I18N.getMessage('my.message.code'));\n
\n" }, { "bintrayPackage": { "name": "jasper", "repo": "plugins", "owner": "puneetbehl", "desc": "Grails jasper plugin", "labels": [ "reporting", "jasper" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/puneetbehl/grails-jasper/issues", "latestVersion": "2.1.0", "updated": "2019-03-08T14:19:00.237Z", "systemIds": [ "org.grails.plugins:jasper" ], "vcsUrl": "https://github.com/puneetbehl/grails-jasper" }, "documentationUrl": "https://puneetbehl.github.io/grails-jasper/", "mavenMetadataUrl": null, "readme": "

Grails Jasper Plugin

\n

\"Build

\n

Usage

\n

For usage information, please see https://puneetbehl.github.io/grails-jasper/

\n

How to build this plugin

\n

run 'grailsw package-plugin'

\n

It will create a plugin archive.

\n

Releasing a new version of this plugin

\n
    \n
  1. In JasperGrailsPlugin.groovy, set the plugin version to a non-snapshot version number (ex 1.6.1)
  2. \n
  3. run 'grailsw publish-plugin --stacktrace'
  4. \n
  5. Update the plugin version in JasperGrailsPlugin.groovy to be a snapshot (ex "1.6.2-SNAPSHOT")
  6. \n
\n" }, { "bintrayPackage": { "name": "jasper-reports", "repo": "grails-plugins", "owner": "9ci", "desc": "Jasper reports Grails Plugin - Jasper reports Grails Plugin", "labels": [ "reporting", "jasper" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/yakworks/spring-grails-kit", "latestVersion": "5.0.10", "updated": "2023-03-09T02:20:53.000Z", "systemIds": [ "org.yakworks:grails-jasper", "org.grails.plugins:jasper-reports" ], "vcsUrl": "https://github.com/yakworks/spring-grails-kit" }, "documentationUrl": null, "mavenMetadataUrl": "https://repo1.maven.org/maven2/org/yakworks/grails-jasper/maven-metadata.xml", "readme": null }, { "bintrayPackage": { "name": "jaxrs-core", "repo": "grails-plugins", "owner": "budjb", "desc": "The jaxrs project is a set of Grails plugins that supports the development of RESTful web services based\r\non the Java API for RESTful Web Services.\r\n\r\nThe jaxrs-core plugin provides the main functionality of the plugin. This plugin does not include an implementing JAX-RS servlet provider, however, so one of the implementation plugins should be included in projects instead.", "labels": [ "jax-rs" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/budjb/grails-jaxrs/issues", "latestVersion": "3.1.0", "updated": "2018-10-01T20:15:04.093Z", "systemIds": [ "org.grails.plugins:jaxrs-core" ], "vcsUrl": "https://github.com/budjb/grails-jaxrs" }, "documentationUrl": "https://budjb.github.io/grails-jaxrs/3.x/latest/", "mavenMetadataUrl": null, "readme": "

\"Build

\n

JAX-RS Plugin for Grails 3.x

\n

See the documentation at http://budjb.github.io/grails-jaxrs/3.x/latest/.

\n" }, { "bintrayPackage": { "name": "jaxrs-integration-test", "repo": "grails-plugins", "owner": "budjb", "desc": "The jaxrs project is a set of Grails plugins that supports the development of RESTful web services based\r\non the Java API for RESTful Web Services.\r\n\r\nThe jaxrs-integration-test plugin provides classes to help with integration testing.", "labels": [ "testing", "jax-rs" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/budjb/grails-jaxrs/issues", "latestVersion": "3.1.0", "updated": "2018-10-01T20:14:31.676Z", "systemIds": [ "org.grails.plugins:jaxrs-integration-test" ], "vcsUrl": "https://github.com/budjb/grails-jaxrs" }, "documentationUrl": "https://budjb.github.io/grails-jaxrs/3.x/latest/", "mavenMetadataUrl": null, "readme": "

\"Build

\n

JAX-RS Plugin for Grails 3.x

\n

See the documentation at http://budjb.github.io/grails-jaxrs/3.x/latest/.

\n" }, { "bintrayPackage": { "name": "jaxrs-jersey1", "repo": "grails-plugins", "owner": "budjb", "desc": "The jaxrs project is a set of Grails plugins that supports the development of RESTful web services based\r\non the Java API for RESTful Web Services.\r\n\r\nThe jaxrs-jersey1 plugin implements the Jersey 1.x JAX-RS implementation.", "labels": [ "jax-rs" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/budjb/grails-jaxrs/issues", "latestVersion": "3.1.0", "updated": "2018-10-01T20:14:58.513Z", "systemIds": [ "org.grails.plugins:jaxrs-jersey1" ], "vcsUrl": "https://github.com/budjb/grails-jaxrs" }, "documentationUrl": "https://budjb.github.io/grails-jaxrs/3.x/latest/", "mavenMetadataUrl": null, "readme": "

\"Build

\n

JAX-RS Plugin for Grails 3.x

\n

See the documentation at http://budjb.github.io/grails-jaxrs/3.x/latest/.

\n" }, { "bintrayPackage": { "name": "jaxrs-restlet", "repo": "grails-plugins", "owner": "budjb", "desc": "The jaxrs project is a set of Grails plugins that supports the development of RESTful web services based\r\non the Java API for RESTful Web Services.\r\n\r\nThe jaxrs-restlet plugin implements the Restlet JAX-RS implementation.", "labels": [ "jax-rs" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/budjb/grails-jaxrs/issues", "latestVersion": "3.1.0", "updated": "2018-10-01T20:15:00.863Z", "systemIds": [ "org.grails.plugins:jaxrs-restlet" ], "vcsUrl": "https://github.com/budjb/grails-jaxrs" }, "documentationUrl": "https://budjb.github.io/grails-jaxrs/3.x/latest/", "mavenMetadataUrl": null, "readme": "

\"Build

\n

JAX-RS Plugin for Grails 3.x

\n

See the documentation at http://budjb.github.io/grails-jaxrs/3.x/latest/.

\n" }, { "bintrayPackage": { "name": "jaxrs-swagger-ui", "repo": "grails-plugins", "owner": "budjb", "desc": "Integrates the Swagger UI with applications using JAX-RS resources.", "labels": [ "jax-rs" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/budjb/grails-jaxrs/issues", "latestVersion": "3.1.0", "updated": "2018-10-01T20:17:06.113Z", "systemIds": [ "org.grails.plugins:jaxrs-swagger-ui" ], "vcsUrl": "https://github.com/budjb/grails-jaxrs" }, "documentationUrl": "https://budjb.github.io/grails-jaxrs/3.x/latest/", "mavenMetadataUrl": null, "readme": "

\"Build

\n

JAX-RS Plugin for Grails 3.x

\n

See the documentation at http://budjb.github.io/grails-jaxrs/3.x/latest/.

\n" }, { "bintrayPackage": { "name": "jenjir", "repo": "maven", "owner": "vahid", "desc": "Grails Jenjir plugin", "labels": [ "jira", "jenkins" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/vahidhedayati/grails-jenkins-plugin/issues", "latestVersion": "3.0.2", "updated": "2016-04-13T21:31:04.183Z", "systemIds": [ "org.grails.plugins:jenjir" ], "vcsUrl": "https://github.com/vahidhedayati/grails-jenkins-plugin" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

jenjir (Jenkins -> Jira) Grails plugin

\n

Grails Jenjir plugin, will interact with Jenkins front end html interface using HTTPBuilder and push summary information to Jira if configured.

\n

You can use websocket feature to watch live builds / view historical build information or trigger a background process that will do the build. So long as userID is provided and Jenkins has authentication enabled, it will attempt to log in as that user without a password (by grabbing token off of Jenkins) This in short means you now have visibility of who triggered a build via Jenkins.

\n

Hooks/Triggers can be put in place to do two additional tasks.

\n

After build trigger known as processurl or if via websocket wsprocessurl

\n

After build summary - which with correct Jira details it will push this summary to all defined tickets within the changelog.

\n
Dependency (Grails 2.X), in your conf/BuildConfig.groovy under plugins add :
\n
\tcompile ":jenjir:0.11"\n
\n

codebase for grails 2.X

\n
Dependency (Grails 3.X), in your build.gradle under plugins add :
\n
\tcompile "org.grails.plugins:jenjir:3.0.2"\n
\n
Plugin will work with tomcat 7.0.54 + (inc. 8) running java 1.7+
\n

Video

\n

Jenjir Part 1 : Older look

\n

Jenjir Part 2 : Update showing multiple builds, basic grails build in Jenkins

\n

Jenjir Part 3 : Update showing Jenkins authentication

\n

Jenjir Part 4 : Non token authentication, custom Parameters

\n

Jenjir part 5 : Automated build/deploy via jssh websockets async non websocket build

\n

Jenjir part 6 : Automated summary to Jira - From Jenkins change log to Jira ticket(s)

\n

Jenjir Test website testjenkins Grails 2X - used in videos\nJenjir Test website testjenkins Grails 3X

\n

Walkthrough

\n

once plugin dependency added to BuildConfig, refreshed dependencies upon run-appp, you will be able to access this plugin via this url:

\n
http://localhost:8080/yourapp/jen\n
\n

This will load in the default index page which asks a few questions in order for you to interact with the given jenkins server/job. This can either be re-used or just make a direct connection using <jen:connect within your gsp.

\n

The plugin adds the following functionality to your existing grails application:

\n
lists current build history items on right hand side
\n

The build history info is sent via WebSockets. If you click an item the Jenkins console logs will be displayed. It displays status of job whether it passed/failed/cancelled/building or queued. If building it will additionally show running time and estimated time according to Jenkins, this was initially achieved by parsing page over and over, now moved locally as a JavaScript that works out difference of estimated time according to jobid/api/json estimateTime value set per Jenkins job. You can click stop to send a stop to backend Jenkins which will stop the build. Scheduled future builds will appeared as queued and you can also cancel them.

\n
Build
\n

This triggers a build and attempts to parse the live Jenkins console output, since it is building the results on Jenkins by default are returned using Ajax. The plugin attempts to do a similar thing but using WebSockets, it grab ready chunks of log output and display back on your page.

\n

How to use

\n

\"Quick

\n

\"Connection

\n
Example : Using taglib to make multiple calls to jenkins:
\n

Controller:\nExampleController.groovy:

\n
\tdef build() {\n\t\tdef goahead=params.goahead\n\t\t[goahead:goahead]\n\t}\n
\n

GSP Page for build.gsp

\n
\n\n<g:form>\n\t<input type="hidden" name="goahead" value="yes">\n\t<input type="submit" value="Build Jenkins job">\n</g:form>\n\n<g:if test="${goahead.equals('yes') }">\n\t<jen:connect divId="firstId" jenserver="localhost" jensport="9090" jensuser="" jenspass=""\n\tjensjob="my_build" jensprefix="" jensfolder="job" jenschoice="build" hideButtons="no" hideBuildTimer="no" />\n\n\t<jen:connect divId="secondId" jenserver="localhost" jensport="9090" jensuser="" jenspass=""\n\tjensjob="my_build2" jensprefix="" jensfolder="job" jenschoice="build" hideButtons="no" hideBuildTimer="no"/>\n</g:if>\n
\n

So we have a button that asks to trigger build - if when clicked - its a self posting form that sets goahead=yes

\n

Then on the same page if this valus equals yes to call taglibs: results below:

\n

\"Output

\n

\"Output

\n

Config.groovy variables required:

\n

Please refer to configuration, this is all of below without comments

\n

Configure properties by adding following to grails-app/conf/Config.groovy under the "jenkins" key:

\n
/*\n* This is the most important configuration\n* in my current version the hostname is being defined by tomcat start up setenv.sh\n* In my tomcat setenv.sh I have\n* HOSTNAME = $(hostname)\n* JAVA_OPTS="$JAVA_OPTS -DSERVERURL=$HOSTNAME"\n*\n* Now as per below the hostname is getting set to this value\n* if not defined wschat will default it localhost:8080\n*\n*/\njenkins.wshostname = System.getProperty('SERVERURL')+":8080"\n// can be overridden via tag lib :  wshostname="something"\n\n\n/* timeout\n* This is the default timeout value for websocket connection\n* If you wish to get user to be timed out if inactive set this to a millisecond value\n*/\njenkins.timeout = 0\n\n\n/*\n* HTTP Builder socket/connection timeouts by default values are as below\n*/\njenkins.http.connection.timeout=10\njenkins.http.socket.timeout=30\n\n\n\n/*\n* Optional : not required - unless different to defaults\n* Jenkins hide Login Pag: default  'no'\n* choices : no/yes\n* Choose if default index page from plugin can be loaded\n*/\njenkins.hideLoginPage = 'no'\n\n\n\n/*\n* Optional : not required - unless different to defaults\n* Jenkins internal consoleLog : default  '/consoleFull'\n*/\njenkins.consoleLog = '/consoleFull'\n// can be overridden via tag lib by definining: jensLog="something"\n\n\n\n/*\n* Optional : not required - unless different to defaults\n* Jenkins internal buildend : default  '/build?delay=0sec'\n*/\njenkins.buildend = '/build?delay=0sec'\n// can be overridden via tag lib : jensbuildend="something"\n\n\n/*\n* Optional : not required - unless different to defaults\n* Jenkins internal progressiveuri : default  '/logText/progressiveHtml'\n*/\njenkins.progressiveuri = '/logText/progressiveHtml'\n// can be overridden via tag lib : jensprogressive="something"\n\n\n/*\n* Optional : not required - unless different to defaults\n* Jenkins hide build/dashboard buttons : default  'no'\n* choices : no/yes\n*/\n\njenkins.hideButtons = 'no'\n\n/*\n* Optional : not required - unless different to defaults\n* Jenkins hide build button : default  'no'\n* choices : no/yes\n*/\njenkins.hideTriggerButton = 'no'\n\n/*\n* Optional : not required - unless different to defaults\n* Jenkins hide dashboard/buildhistory button : default  'no'\n* choices : no/yes\n*/\njenkins.hideDashBoardButton = 'no'\n\n/*\n* Optional : your own custom processing url for when builds are triggered\n* provide a full url back to a controll action so that when it completes a build\n* notification is sent to controller and you can then call  further services on output\n*/\njenkins.processurl = "http://localhost:8080/testjenkins/test/parseJenPlugin"\n\n\n/*\n* Optional : your own custom processing url for when builds are triggered\n* provide a full url back to a controll action so that when it completes an extra \n* action button is provided\n* the process url could in theory call another end point to lets say jssh and do a live deployment\n*/\njenkins.wsprocessname = "Deploy"\njenkins.wsprocessurl = "http://localhost:8080/testjenkins/test/parseJenPluginDeploy"\n\n\n\n// Auto submit wsprocess url ?\njenkins.autosubmit = "yes"\n\n// Enhanced option for secondary action \n// If this is set as true it will only attempt to call \n// processurl/wsprocess url triggers if result was successfull\njenkins.process.on.success = true\n\n/* 0.3 feature \n* if app has wsprocessurl additional button to buildOnly appears \n* which can be disabled if this is set to no\n*/\njenkins.show.build.only.button = "yes"\n\n\n// If once built you wish to send summary enable this as true\njenkins.sendSummary = true\n\n// This must also be set to yes to show summary and send it once built. \njenkins.showsummary = "yes"\n\n\n\n/*\n* Jira configuration - refer to summary section below:\n*  Don't enable any of this if you are not looking to push anything to Jira.\n*/\njenkins.sendtoJira = 'yes'\n\njenkins.jiraServer = 'http://jira-test.yourdomain.com'\njenkins.jiraUser = 'automation_account'\njenkins.jiraPass = 'automation_account_password'\n\n/*\n* This is the url usually to access the ticket for viewing - used to test if ticket is valid\n* if not defined will default to /browse/\n*/\njenkins.jira.AccessUri = "/browse/"\n\n\n/* \n * There are various send types :\n * comment -- adds the summary output as a comment to valid jira ticket \n * customfield -- adds the summary output to provided customfield ID - please note customfield must have correct screen perms for it to work\n * updatecustomfield -- gets current input if different to new input adds them together to customfield\n * description -- updates ticket description with the summary\n * comdesc -- updates ticket description and adds a comment both containing the summary\n */\njenkins.jiraSendType = 'customfield' \n// If you have defined working option customfield then define the customfield id for this configuration item:\njenkins.customField = '12330' // the id of your customfield\n\n\n/*\n* API Api Info - send this as part of summary?\n*/\njenkins.sendApi = true  // true/false - by default false\n// SendApi - sub fields:\n/* API ChangeSet - send this as part of summary?*/\njenkins.sendChangeSet = true  // true/false - by default false\n/*API culprits - send this as part of summary?*/\njenkins.sendCulprits = true  // true/false - by default false\n/*API full display name - send this as part of summary?*/\njenkins.sendFdn = true  // true/false - by default false\n/*API Build Id - send this as part of summary?*/\njenkins.sendBuildId = true  // true/false - by default false\n/*API Build UserID/Name - send this as part of summary?*/\njenkins.sendBuildUser = true  // true/false - by default false\n\n/*\n* Jenkins BuildID Change Logs - send this as part of summary?\n*/\njenkins.sendChanges = true  // true/false - by default false\n\n/*\n* Jenkins BuildID Specific parse Info - send this as part of summary?\n*/\njenkins.sendParseConsole = true  // true/false - by default false\n/*LogParser Look for Building Work space ? send this as part of summary?*/\njenkins.parseBuildingWorkSpace = true  // true/false - by default false\n/*LogParser Look for Building ? send this as part of summary?*/\njenkins.parseBuilding = true  // true/false - by default false\n/*LogParser Look for Done Creating? send this as part of summary?*/\njenkins.parseDoneCreating = true  // true/false - by default false\n/*LogParser Look for Last valid trans ? send this as part of summary?*/\njenkins.parseLastTrans = true  // true/false - by default false\n\n\n/* Buttons on websocket page :\n* set these as you see here change to no if you wish \n* not for them to appear on the webpage.\n* you can override these values from within either taglib call too\n*/\njenkins.summaryViewButtons = "yes"\njenkins.summaryFileButton = "yes"\njenkins.summaryChangesButton = "yes"\n\njenkins.jiraButtons = "yes"\njenkins.jiraOverwriteButton = "yes"\njenkins.jiraAppendButton = "yes"\njenkins.jiraCommentButton = "yes"\n\n\n/*\n* formType can be defined as taglib (overrides Config.groovy )\n* defines the wsprocessurl form type (either normal which takes over page or remote which updates divId)\n* if remote it will create new element ID called return_${divId} what ever you defined divId to be \n* so if multi call - on each call a return_ element is created\n*/\njenkins.formType = "normal" // either normal or remote\n\n// If you define formType = "remote" you will also need two more config or tag lib calls:\n// Both of these should actually be part of above wsprocess url \njenkins.remoteController= 'Your controller that is being called'\njenkins.remoteAction = 'Your action' \n\n
\n

When submitted, the controller has been set to recieve parameters and call a tag lib which can also be used by you guys to call a jenkins build on the fly from within your gsp.

\n
<jen:connect\ndivId="someId"\njenserver="${jenserver }"\njensport="${jensport}"\njensuser="${jensuser}"\njenspass="${jenspass}"\njensjob="${jensjob}"\njensprefix="${jensprefix}"\njensfolder="${jensfolder}"\njensport="${jensport}"\njenschoice="${jenschoice}"\n\n/>\n
\n

Optional override taglibs: (Refer to above Config.groovy to understand what these are:)

\n
<jen:connect\n....\nhideButtons="${hideButtons }"\nhideTriggerButton="${hideTriggerButton }"\nhideDashBoardButton="${hideDashBoardButton }"\njensLog="something"\nwshostname="something"\njensprogressive="something"\njensLog="something"\ndynamicParams = "['deployType':['background', 'live']]"\ncustomParams="[appId: '123', appName: 'crazyApp', appEnv: 'test' ]"\nprocessurl="http://your_process_url/controller/action"\nwsprocessurl="http://your_process_url/controller/action"\nwsprocessname="Deploy code"\n\n// Buttons\nsummaryViewButtons = "yes"\nsummaryFileButton = "yes"\nsummaryChangesButton = "yes"\n\njiraButtons = "yes"\njiraOverwriteButton = "yes"\njiraAppendButton = "yes"\njiraCommentButton = "yes"\n// if you have wsprocess url - 2 buttons would appear \nbuildOnlyButton = "yes"\n\nformType = "normal" // normal or remote\n// if remote define these:\nremoteController = 'Your controller that is being called'\nremoteAction = 'Your action' \n/>\n
\n

customParams - if you have configured a processurl in your config you can pass values back

\n

Results are typically returned to process url like this:

\n
[files:{"type":"WAR","name":"target/testmodaldynamix-0.1.war"},result:SUCCESS, token:9cf496bb07021a1d788f8838159291cf, buildUrl:http://localhost:9090/job/my_build/175, customParams:{appId=123, appName=crazyApp, appEnv=test}, buildId:175, job:/job/my_build, server:http://localhost:9090, user:cc, action:parseJenPlugin, format:null, controller:test]\n
\n
Refer further down on information on how to retrieve customParams
\n

So long as you provide the above values from within a gsp page it should load in the results back on the page.

\n

You should be able to call it multiple times and provide different divId's for each call - to get multiple builds on one gsp page.

\n

Tested on recent/older variants of Jenkins. May still fail on others, please post an issue with specific Jenkins version for me to look into.

\n

Alternative more direct connect tag lib call:

\n
<jen:dirconnect\n\t\tdivId="someId"\n\t\tjensurl="http://jenkins-server:port/job/jobname"\n\t\tjensuser="current_user"\n\t\tjenschoice="dashboard"\n\t\tjensjob="jobname"\n\t/>\n
\n

Optional - if you have configured a processurl in your config you can pass values back\nAll optional above should work

\n
processurl="http://your_process_url/controller/action"\nwsprocessurl="http://your_process_url/controller/action"\nwsprocessname="Deploy code"\ncustomParams="[appId: '123', appName: 'crazyApp', appEnv: 'test' ]"\n
\n

Summary information:

\n

There is a new option called summary that appears next to the build ID's this Summary tries to grab information from 3 segments of Jenkins and if configured will push this information to a customfield on Jira.

\n

It queries:

\n

The build Logs and tries to grab working folder, produced file and a line called last trans if it exists.\nChange screen - grabs all related build changes to be pushed through\nApi summary - a variety of information from the api output.

\n

The most important aspect of this is that within the changes logs, it looks for a ticket ID either seperated by : or -

\n

so

\n
AB-1102 : Description  \n
\n

or :

\n
AB-1102 - Description\n
\n

Where AB-1102 will be the ticket number, this will then update this jira ticket with the summary provided

\n

\"Jira

\n

Refer to above configuration items for the required jenkins configuration in your config.groovy.

\n

It will parse through the changes logs, and for each ticket found - it will attempt to push the response to all tickets.

\n

For the summary information to work properly I found I had to add two blank configuration items to my config.groovy:

\n
jenkins.processurl=""\n\njenkins.wsprocessurl=""\n
\n

These could actually be filled with a value, its just if not defined it returns some groovy object

\n

####Async Build (Non Websocket)\nThis will trigger a service that does a background build, whilst building it will check for completion, once completed it will trigger process url\nand send back results to it.

\n
<jen:asyncBuild\n\n\turl="http://host:post/job/JOB_NAME"\n\t\n\tcustomParams="[appId:'MyCurrentJob', appDetails: 'Something']"\n\t\n\t\n\tjensuser="MyUserId"\n\t\n\t\n\tprocessurl="http://localhost:8080/testjenkins/test/myresults"\n\t\n\t\n\t/>\n
\n

The processurl - is a background process that has no interaction with your front end view, runs in the background. When a job completes it returns its status plus a variety of other parameters to the given url.

\n

The wsprocessurl - is a url which wsprocessname is the display name for the link within your websocket connected page. Once the job is completed a button is provided on the same websocket page to trigger the next controller/action which could in short be another taglib call that calls yet another websocket to process something else.\nYou can enable both processurl and wsprocessurl - they could be doing different things if needs be. It would not be a good idea to call the same controller/action since it will then lead to duplicated actions.

\n

Authenticated Jenkins howto:

\n

Once you have configured global security of some form on your Jenkins server. Authentication should work via Jenkins so long as you either provide just the username to the initial form, or via the taglib call.

\n
The plugin will attempt to grab the user authToken from the given server, if it can successfully retrieve this without authentication then the userToken is automatically set.
\n

So by simply providing a valid username, the plugin will try do the rest and authenticate as the given user. With this you can easily gain a better overview of who is trigerring the build on Jenkins backend.

\n

Whilst building if the current user has got authenticated then the user will appear above build logs otherwise current user will show anonymous.

\n
To manually define authToken per user(known as jenspass)
\n

First thing first, you need to enable authentication on Jenkins, our systems uses AD plugin and connects a user through to AD.\nOnce a user has logged in then goto:

\n
    \n
  1. Your Jenkins server:
  2. \n
\n

http://your_jenkins:port/user/USERID/configure

\n

Click on show API Token (This is an example token)\n9a997cc1a954ac3a5ac59ea97c17a851

\n

With this information now login using the front end using the username and the token as the password - this now triggers builds as the user.

\n
customParams Retrieval
\n

This is our example parseJenplugin call, the results are actually in JSON format, so as per what fed in in above example. I am now extracting each value on processurl:

\n
def parseJenPlugin() { \n\t\tprintln ":::> ${params} <:::"\n\t\t\n\t\t// This is an example itterating through files:\n\t\t// files:{"type":"WAR","name":"target/testmodaldynamix-0.1.war"}\n\t\t// where key will be type or name\n\t\t// value will by type of file and file name as per jenkins output in the build logs.\n\t\t// you may wish to set :\n\t\t//jenkins.parseBuilding = false\n\t\t// in config.groovy so that Building files also do not appear in :\n\t\t//jenkins.parseDoneCreating = true\n\n\t\tif (params.files) {\n\t\t\tJSONObject files1=JSON.parse(params.files)\n\t\t\tfiles1.each { k,v->\n\t\t\t\tprintln "-- FILE_TYPE: $k ||| FILE_NAME: $v"\n\t\n\t\t\t}\n\t\t}\n\t\t\n\t\t\n\t\tdef pp=params.customParams\n\t\tdef apps\n\t\tif (pp) {\n\t\t\tdef data = JSON.parse(params.customParams)\n\t\t\tdef appId=data?.appId\n\t\t\tdef appName=data?.appName\n\t\t\tdef appEnv=data?.appEnv\n\t\t\tprintln "--- Our Custom values passed from initial taglib call are:"\n\t\t\tprintln " AppID: $appId | AppName: $appName | AppEnv: $appEnv"\n\t\t\t/*\n\t\t\t *    <jen:connect divId="firstId" \n\t\t\t\t\t.....\n\t\t\t\t\tcustomParams="[appId: '123', appName: 'crazyApp', appEnv: 'test' ]"\n\t\t\t\t\t/>\n\t\t\t\t\t\n\t\t\t\t\twhich has produced:\n\t\t\t\t\t\n\t\t\t\t\t:::>[files:{"type":"WAR","name":"target/testmodaldynamix-0.1.war"},result:SUCCESS, token:9cf496bb07021a1d788f8838159291cf, buildUrl:http://localhost:9090/job/my_build/182, customParams:{appId=123, appName=crazyApp, appEnv=test}, buildId:182, job:/job/my_build, server:http://localhost:9090, user:cc, action:parseJenPlugin, format:null, controller:test] <:::\n--- Our Custom values passed from initial taglib call are:\n AppID: 123 | AppName: crazyApp | AppEnv: test\n\n\t\t\t\t\t\n\t\t\t * \n\t\t\t */\n\t\t\t\n\t\t\t\n\t\t}\n\t\trender ""\n\t}\n
\n

Jenjir Change information:

\n
0.10-SNAPSHOT - Environment Issue if attempting to run as a plugin within development project\n\n0.10 - \tIssues with gsp javascript - variables not bound to dynamic call - issue with previous size - \n\t\tnow defaulted to first array value for any amount of input. Since initial value may not be default action\n\t\t\n0.9\t-\tMinor issues - config options in endpoint set to default to '' if not set - was returning object before.\n\t\tCheck to see if dynamicValues size = 1 if so then set this to be the default value via websockets on _process.gsp\n\t\t\n0.8 - \tMinor bugs : if jira front end buttons disabled -small tag was left open making list smaller and smaller - fixed.\n\t\tNewly introduced successProcess in jenService required bid as String from the local call - causing issues doing next phase action\n\t\tNewly added Additional function button appeared on all passed jobs - only first requires this value. - fixed\n\t\t\n0.7\t-\tBug in appendCustomField + customField functions fixed. New button added labelled as wsprocessname Value. This gives addtional functionality \n\t\tto first in list - or last Build ID - if it built successfully a trigger to trigger secondary action is now available.\n\t\tIf a build is triggered this icon disappears since the workspace is likely to no longer include last built file.\n\t\t\n\t\t\n0.6\t-\tDynamicParams added as an additional input to <jen:connect <jen:dirconnect\n\t\tThis is defined by a key followed by values  \n\t\tdynamicParams = "['deployType':['background', 'live']]"\n\t\tWith this set a select box is created on frontend which when user selects defined option the value is passed back to \n\t\tprocessurl or wsprocessurl after build is completed \n\t\tThis is now allowing dynamic value selection alongside the build/deploy task\n\t\t\n\t\t\n0.5 - \tHoping this be the last update for a while the remoteForm functionality would have only worked on autoSubmit=yes\n\t\tThis has now been corrected so remoteForms will work on autosubmit true or not.\n\t\t\n0.4 - \tremote form submission feature enabled meaning on multi build tasks with multi element all results should be \n\t\treturned/triggered on the same page that did the call. Refer to configuration items for remoteform options (formType)\n\t\t \n0.3 - \tCleanup of config calls within services. Addition just Build button added if end app has processurl name/action defined.\n\t\tBetter logics around displaying wsprocessname with Build button.\n\t\t\n0.2 - \tTidy up - moved getlastBuild as lastBuild into jenService - removed duplicate calls. \n\t\tFixed wsprocess/process urls to both include files produced json as output params\n\t\tAdded socket/http connection timeouts to HTTPBuilder calls.\n\t\t\n0.1 - release\n
\n

Jenjir Issues/Bugs:

\n
1. Prefix jenkins servers.
\n

If you have a server with a prefix then you will find the quick connect method will not work for you, you need to use the manaully full detail connection method since the prefix is required for the url and uri.

\n" }, { "bintrayPackage": { "name": "jesque", "repo": "grails-plugins", "owner": "ctoestreich", "desc": "Grails Jesque Plugin", "labels": [ "jedis", "jesque", "queue", "redis" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/Grails-Plugin-Consortium/grails-jesque/issues", "latestVersion": "1.2.1", "updated": "2017-04-19T17:22:29.457Z", "systemIds": [ "org.grails.plugins:jesque", "org.grails.plugins:grails-jesque" ], "vcsUrl": "https://github.com/Grails-Plugin-Consortium/grails-jesque" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": null }, { "bintrayPackage": { "name": "jesque-admin", "repo": "plugins", "owner": "uberall", "desc": "Admin UI for the Grails Jesque Plugin", "labels": [ "jesque" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/uberall/jesque-admin/issues", "latestVersion": "0.6.9", "updated": "2020-08-21T18:35:05.302Z", "systemIds": [ "org.grails.plugins:jesque-admin", "org.grails.plugins:grails-jesque-admin" ], "vcsUrl": "https://github.com/uberall/jesque-admin" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

jesque-admin

\n

A User interface for Jesque powered by grails and react.

\n

Installation

\n

Just add jesque-admin to your dependencies

\n
dependencies {\n    ...\n    compile 'org.grails.plugins:jesque-admin:0.6.6'\n}\n
\n

Usage

\n

Make sure that jesque is enabled. If you do not have the "default mapping for controllers" in your UrlMappings.groovy you will have to add mappings for jesque-admin to your UrlMappings.groovy\nThis plugin does not expose any UrlMappings by itself for security reasons. Job payloads can hold sensitive data and having an "open" jesque-admin interface can lead to breaches.

\n
"/jesque/"(controller: 'jesqueAdmin', action: 'index')\n"/jesque/api/overview"(controller: 'jesqueAdmin', action: 'overview')\n"/jesque/api/queues"(controller: 'jesqueAdminQueue', action: 'list')\n"/jesque/api/queues/$name"(controller: 'jesqueAdminQueue', action: 'details', method: "GET")\n"/jesque/api/queues/$name"(controller: 'jesqueAdminQueue', action: 'remove', method: "DELETE")\n"/jesque/api/jobs"(controller: 'jesqueAdminStatistics', action: 'jobs', method: "GET")\n"/jesque/api/jobs"(controller: 'jesqueAdminJob', action: 'enqueue', method: "POST")\n"/jesque/api/jobs/removeDelayed"(controller: 'jesqueAdminJob', action: 'removeDelayed', method: "POST")\n"/jesque/api/jobs/failed"(controller: 'jesqueAdminJob', action: 'failed', method: "GET")\n"/jesque/api/jobs/failed/$id"(controller: 'jesqueAdminJob', action: 'retry', method: "POST")\n"/jesque/api/jobs/failed/$id"(controller: 'jesqueAdminJob', action: 'remove', method: "DELETE")\n"/jesque/api/jobs/failed"(controller: 'jesqueAdminJob', action: 'clear', method: "DELETE")\n"/jesque/api/jobs/triggers"(controller: 'jesqueAdminJob', action: 'triggers', method: "GET")\n"/jesque/api/jobs/triggers/$name"(controller: 'jesqueAdminJob', action: 'deleteTrigger', method: "DELETE")\n"/jesque/api/jobs/$job"(controller: 'jesqueAdminStatistics', action: 'list', method: "GET")\n"/jesque/api/workers"(controller: 'jesqueAdminWorker', action: 'list', method: 'GET')\n"/jesque/api/workers"(controller: 'jesqueAdminWorker', action: 'manual', method: 'POST')\n"/jesque/api/workers/$name"(controller: 'jesqueAdminWorker', action: 'remove', method: 'DELETE')\n"/jesque/api/workers/pause"(controller: 'jesqueAdminWorker', action: 'pause', method: 'GET')\n"/jesque/api/workers/resume"(controller: 'jesqueAdminWorker', action: 'resume', method: 'GET')\n
\n

You can freely change "/jesque/api/" to whatever you want but i highly recommend not to change anything that comes after that.

\n

Job Statistics

\n

jesque-admin comes with mechanics to gather statistics like start, end and runtimes of Jobs. All this is done by using a specific Worker Listener.\nAll you have to do is enable the statistics collecting feature in you application.yml (or .groovy):

\n
grails:\n    jesque:\n        statistics:\n          enabled: true\n          max: 100 // the maximum number of statistics PER JOB CLASS to store\n
\n

you also have to set JesqueJobStatisticsWorkerListener as a custom listener:

\n
grails:\n    jesque:\n        enabled: true\n        custom:\n          listener:\n            clazz: grails.plugins.jesque.admin.JesqueJobStatisticsWorkerListener\n
\n

After restarting your App you should find a list menu item under "jobs" in jesque-admin which lets you browse past jobs being processed.

\n

Development

\n

If you want to extend jesque-admin or help developing it further simply start by:

\n
    \n
  1. Run gradle bootRun -Djesque.admin.devel=true (or grails run-app or run the main method in Application.groovy whatever you prefer)
  2. \n
  3. Run npm i in the root folder of this plugin
  4. \n
  5. Run npm run devel
  6. \n
\n

Note: you need node.js version 6.9.0

\n

In order to build the project run the following commands:

\n
    \n
  1. npm run package
  2. \n
  3. ./gradlew publishToMavenLocal
  4. \n
\n" }, { "bintrayPackage": { "name": "jms", "repo": "plugins", "owner": "gpc", "desc": "Grails jms plugin", "labels": [ "jms", "messaging" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/gpc/jms/issues", "latestVersion": "4.0.2", "updated": "2024-02-15T14:45:33.000Z", "systemIds": [ "io.github.gpc:jms", "org.grails.plugins:jms" ], "vcsUrl": "https://github.com/gpc/jms" }, "documentationUrl": "https://gpc.github.io/jms/latest/", "mavenMetadataUrl": "https://repo1.maven.org/maven2/io/github/gpc/jms/maven-metadata.xml", "readme": "JMS integration for Grails. See documentation for more information." }, { "bintrayPackage": { "name": "joda-time", "repo": "plugins", "owner": "gpc", "desc": "Joda-Time Plugin", "labels": [ "date" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/gpc/joda-time/issues", "latestVersion": "2.1.0", "updated": "2018-06-19T11:29:37.127Z", "systemIds": [ "org.grails.plugins:joda-time" ], "vcsUrl": "https://github.com/gpc/joda-time" }, "documentationUrl": "https://gpc.github.io/joda-time/", "mavenMetadataUrl": null, "readme": null }, { "deprecated": "Source repository for this entry is archived. This entry should probably be removed from the registry.", "bintrayPackage": { "name": "json-annotations-marshaller", "repo": "plugins", "owner": "tony75", "desc": "Grails 3 plugin for managing JSON marshalling through annotations", "labels": [ "json" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "", "latestVersion": "v1.0", "updated": "2016-03-31T16:16:47.970Z", "systemIds": [ ], "vcsUrl": "https://github.com/tony75/grails3-json-annotations-marshaller" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

json-apis

\n

Grails plugin for managing multiple JSON apis using domain class annotations

\n

The goal of this plugin is to help convert Grails domain classes into various\nJSON representations needed in different parts of your web application or to\nsupport various API versions.

\n

Features:

\n\n

Example of use

\n

Several API variants can be easily defined in domain classes by annotating properties with\nJsonApi and providing a list of API profile names under which that property should appear in the\nresulting JSON. Marking a property with the JsonApi annotation but providing no API names will\ninclude that property in all APIs. The database identity property will always be included\nautomatically. One could for instance define the following domain class:

\n
import grails.plugins.jsonapis.JsonApi\n\nclass User {\n\t@JsonApi\n\tString screenName\n\n\t@JsonApi('userSettings')\n\tString email\n\n\t@JsonApi(['userSettings', 'detailedInformation'])\n\tString twitterUsername\n}\n
\n

Then in the controller one would call the desired named JsonApi configuration to get only\nthe fields defined for that API. The following code:

\n
JSON.use("detailedInformation")\nrender person as JSON\n
\n

...would convert the person object into JSON containing the id, screenName and twitterUsername\nproperties but not the email. It works for collections as well, converting each collection\nmember using the same API profile that was used to convert the parent:

\n
static hasMany = [\n\tpets: Pet\n]\n@JsonApi('detailedInformation')\nSet pets\n
\n

To include a domain object's parent in a JSON API, declare a belongsTo property explicitly\nand annotate it with JsonApi (but be careful not to create circular paths by including both\nends of a belongsTo/hasMany pair):

\n
static belongsTo = [\n\tuser:User\n]\n\n@JsonApi('petDetails') \nUser user\n
\n

JSONBuilder is supported, too:

\n
JSON.use("userSettings")\nrender(contentType: "text/json") {\n    user = User.first()\n    pet = Pet.first()\n}\n
\n

Future plans

\n\n" }, { "bintrayPackage": { "name": "jssh", "repo": "maven", "owner": "vahid", "desc": "Grails j2ssh plugin", "labels": [ "ssh" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/vahidhedayati/jssh/issues", "latestVersion": "3.0.2", "updated": "2016-04-13T21:24:25.384Z", "systemIds": [ "org.grails.plugins:jssh" ], "vcsUrl": "https://github.com/vahidhedayati/jssh/" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

jssh

\n

Side note - similar / related projects

\n\n

Grails jssh Plugin based on j2ssh library, provides ssh connection with features/facilities to execute remote shell commands. Provides connection via websockets as well as ajax/polling.

\n

Websocket ssh interaction can be incorporated to an existing grails app running ver 2>+. Supports both resource (pre 2.4) /assets (2.4+) based grails sites. Plugin will work with tomcat 7.0.54 + (8 as well) running java 1.7 +

\n
Dependency (Grails 2.X):
\n
compile ":jssh:1.10"\n
\n

codebase for grails 2.X

\n
Dependency (Grails 3.X) :
\n
\tcompile "org.grails.plugins:jssh:3.0.2"\n
\n

This plugin is a web based basic putty i.e. sshkey or username/password. It provides a variety of taglib calls that you can call from within your application to then interact with SSH connection(s) to Unix/Linux/OSx machines.

\n

Once you have successfully configured connected. Your browser will provide something similar to a shell console and with the latter Websocket calls you can literally interact live with your SSH connection(s).

\n

Config.groovy additions required:

\n

Config.groovy variables

\n

Test site:

\n

grails 3 demo site refer to application.groovy for config values

\n

grails 2 demo site

\n

Change Release information

\n

Change information

\n

Videos

\n

jssh 1.6 admin interface / cloning of accounts + viewing historical logs/commands

\n

jssh 1.3 sshuser configuration per webuser + command restrictions(blacklist) / command rewrites

\n

jssh 1.0 broadcast ssh commands to multiple remote hosts 8 Mins

\n

Video of jssh 0.9, whilst waiting on creations of stuff there was some discussion into the back-end plugin code and how it interacts via websockets:

\n

jssh 0.9 full walk through 43 mins? wow a lot of BS :)

\n

Interaction Methods:

\n

1> Socket Client/Server

\n
mutli-connection broadcasting to multiple SSH connections
\n

New Client/Server Websocket SSH tag lib call

\n

1.3 Command blacklist / command rewrites

\n

1.11 j2ssh some updates to the inner workings, issues getting it to work on latest ubuntu, are you having issues getting j2ssh to work with your open-ssh server ? if so read this

\n

J2ssh issues with latest open-ssh-server

\n

J2ssh was not working on the latest ubuntu for me, refer to the above link to find changes in debian ssh roll out.

\n

To fix j2ssh and latest openssh-server issue read this

\n

Sessions

\n
\n<jssh:conn \n    hostname="${hostname}" \n    username="${username}"\n\tport="${port}" \n\tpassword="${password}"\n\tuserCommand="${userCommand}"\n\trealuser="${session.username}"\n\tjsshUser="${jsshUser}"  //do not set this if you want auto gen id  \n\tdivId="${divId}"\n\tenablePong="true"\n\tpingRate="50000"\n />\n\n
\n

2A> Socket Method

\n

jssh-websocket-taglib-call

\n

wiki on jssh existing app using websockets

\n

Socket taglib with pingpong

\n
<jssh:socketconnect \nusername="${username }"\npassword="${password }"\nhostname="${hostname}" \nuserCommand="${userCommand}"\ndivId="${divId}"\nhideWhatsRunning="${hideWhatsRunning }"\nhideDiscoButton="${hideDiscoButton }"\nhidePauseControl="${hidePauseControl }"\nhideSessionCtrl="${hideSessionCtrl }"\nhideConsoleMenu="${hideConsoleMenu}"\nhideSendBlock="${hideSendBlock}"\nhideNewShellButton="${hideNewShellButton}"\nenablePong="true"\npingRate="50000"\n/>\n
\n

2B> Socket Method -- Multipe calls - remoteForm -

\n

As above but: refer to plugin connectSsh/index page and go to remote Form..\nI have used this method and called it many times on 1 page by reusing the <jssh:socketconnect tag multiple times.

\n
<jssh:socketconnect \n...\n  divId="${divId}" />\n<div id="${divId}"></div>\n
\n

3> Ajax Taglib

\n

wiki on jssh existing app using ajax polling

\n

ajax/polling tag lib call

\n
<jssh:ajaxconnect hostname="${hostname}" username="${username}"\n\tport="${port}" password="${password}"\n\tuserCommand="${userCommand.encodeAsJavaScript()}"\n\tjsshUser="${jsshUser}"  />\n
\n

4> Admin interface (part of 1.4 release)

\n

A new configuration item has been added to jsshUser DB table, called permissions.

\n

If you want to use this plugin and define admin outside of the scope of usual app interaction, then you could try adding default admin accounts through your :

\n

BootStrap.groovy

\n

Otherwise you could add the following to your Config.groovy and any accounts generated from there on via the tool would have access to admin interface.\nYou could do this to start with then change the defaultperm="user"

\n
jssh.defaultperm="admin"\n
\n

In order to access admin interface you need to call this taglib :

\n
<jssh:loadAdmin jsshUser="your_userId" />\n
\n

If you have added the admin account via Config.groovy then the account is not generated as yet so you need to make an initial connection to create the user:

\n
\n<jssh:conn \njsshUser="your_userId"\nrealUser="your_userId"\njobName="vahidsJob"\nusername="your_userId"\npassword=""\nhostname="HOSTNAME" \nuserCommand="tail -f /var/log/tomcat/catalina.out"\ndivId="abaa"\nenablePing="true"\npingRate="60000"\n/>\n
\n

Once you have hit the initial start page and created that jssh account to match the same jsshUser as the admin account and have defined admin permission for the user, the admin interface will then come alive.

\n

5> Specific user connection select boxes.

\n

This is the component within admin menu that allows the end user to connect to a group of servers. It has been recreated as a taglib call so now you as the end user can define when/where your website users can choose to connect to a group of servers.

\n

Most basic call with full access to all its features:

\n
<jssh:connectUser \njsshUser="${session.username}"  \n/>\n\n
\n

A more defined specific call with global broadcast and send blocks pers sever blocked, this also defines primary command to be run upon group selection:

\n
<jssh:connectUser \njsshUser="${session.username}"  \nuserCommand="something"\nhideSendBlock="YES" \nhideBroadCastBlock="YES"\n/>\n
\n
Misc Calling methods:
\n

Taglib example on resources based grails app

\n

Taglib example on assets based grails app

\n

gsp call

\n

Extendable css div box

\n

Easy scrolling tailing log test

\n

Usercommand hacks

\n

Bootstrap/jquery switch method

\n

Screenshots

\n

SSH Keys:

\n

Why pingpong ?

\n" }, { "bintrayPackage": { "name": "karman-grails", "repo": "karman", "owner": "bertramlabs", "desc": "Karman is a standardized / extensible interface plugin for dealing with various cloud services including Local, S3, and Openstack.", "labels": [ "cloud" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/bertramdev/karman-core/issues", "latestVersion": "2.3.2", "updated": "2024-09-18T16:10:31.000Z", "systemIds": [ "com.bertramlabs.plugins:karman-grails" ], "vcsUrl": "https://github.com/bertramdev/karman-core" }, "documentationUrl": "https://bertramdev.github.io/karman-core/", "mavenMetadataUrl": "https://repo1.maven.org/maven2/com/bertramlabs/plugins/karman-grails/maven-metadata.xml", "readme": "

Karman Core

\n

Welcome to Karman. Karman is a standardized / extensible interface plugin for dealing with various cloud services.\nIn the beginning, Karman will focus on providing rock solid simplified interfaces for storing / retrieving files in the cloud.

\n

Features:

\n\n

Modules:

\n\n

Documentation

\n

Currently the majority of the documentation is in the Grails Plugin

\n

http://bertramdev.github.io/karman

\n

The Beginnings of a GroovyDoc area also available here:

\n

http://bertramdev.github.io/karman-core

\n

Contributions

\n

All contributions are of course welcome as this is an ACTIVE project. Any help with regards to reviewing platform compatibility, adding more tests, and general cleanup is most welcome.\nThanks to several people for suggestions throughout development.

\n" }, { "bintrayPackage": { "name": "kml", "repo": "maven", "owner": "vahid", "desc": "Grails Global postal code to address resolving Plugin KML Map Boundary utilities loader editor. Postcodes restricted to customised boundaries", "labels": [ "kml" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/vahidhedayati/grails-kml-map-plugin/issues", "latestVersion": "0.7", "updated": "2019-12-10T11:12:13.918Z", "systemIds": [ "org.grails.plugins:kml", "org.grails.plugins.kml:kml", "grails.kml.plugin:kml" ], "vcsUrl": "https://github.com/vahidhedayati/grails-kml-map-plugin" }, "documentationUrl": "https://vahidhedayati.github.io/grails-kml-map-plugin/", "mavenMetadataUrl": null, "readme": "

grails-kml-plugin

\n

This is a very powerful plugin that does multiple things:

\n

A plugin to read raw kml file in - load google maps and overlay kml boundaries over map geo locations, international postcode lookup & resolve address from postcode feature

\n

1. Post/Zip code lookup globally and resolves as much of address as possible

\n

2. If map enabled draws out

\n
2.1 Boundary / area if exists
\n
2.2 places geo location of location on map
\n

3. Provides KML Utils:

\n
3.1 Parsing utils (Google Map overlay) - read below
\n
3.2 Edit KML Files via plugin and update a boundary
\n

Please refer to YouTube video to understand all of above a bit better

\n

How to install: Dependency Grails 3 (build.gradle):

\n
compile "org.grails.plugins:kml:0.4"\n
\n
\n

Demo project (grails 3.3.8)

\n
\n
\n

YouTube videos:

\n
\n

Boxset - play all 3 as a playlist

\n

Part 1 Walk through urls and simple usage of plugin - very basic

\n

Part 2 Walk through of how to build on new grails project from scratch

\n

Part 3 Talk through code process / steps

\n
\n

Java docs for classes

\n
\n

Configuration values for your application.yml application.groovy in my case:

\n
kmlplugin{\n    //TO USE MAP API FEATURE NEEDS TO BE ENABLED\n    GOOGLE_API_KEY='YOUR GOOGLE API KEY'\n    //This is total amount of local areas to collect for editing KML  \n    MAX_AREAS=30\n\n    //How far to look for local areas in miles\n    MAX_DISTANCE=30\n\n    //This defines to enable map\n    ENABLE_MAP_LOOKUP=true\n\n    //By default treated as false\n    DISABLE_LAT_LNG_LOOKUP=false\n\n    // If you don't have API feature enabled on key disable this you get a developer map instead\n    MAP_HAS_API_ENABLED=false\n\n  \n    //2 char country code of where your _default.kml belongs to so we can look up area names\n    KML_COUNTRY='UK'\n\n    // Internal folder to manage KML files - create and ensure web user has access\n    KML_LOC="/opt/kmlplugin/_map/KML/"\n    KML_HISTORY="/opt/kmlplugin/_map/KML_HISTORY/"\n\n    //Drop this file in KML_LOC root folder - refer to notes below\n    KML_DEFAULT="_default.kml"\n\n    //This will re-run - recreate entries from _default.kml\n    //if you are running in dev on h2 db - it is worth enabling this to add areas to db upon boot\n    KML_RESET_FROM_DEFAULT=false\n}\n
\n

Upon Start Available urls:

\n

1. Lookup service : http://localhost:8080/lookup

\n

This provides a page that given country / postcode will attempt to:

\n
\n

1.1: Lookup postcode and return as much of address as possible

\n
\n
\n

1.2. If ENABLE_MAP_LOOKUP is set to true and GOOGLE_API_KEY has valid API access\nWill load map, put postcode on map\n& if KML boundaries loaded and matches will load in the area overlay on the map.

\n
\n
\n

1.3 To disable features you can add any or all these to url line:

\n
\n\n

Other examples:

\n\n

2. TagLib call

\n

All passed variables to map and instance are not required but to show what above url params can be either posted or done as per above with instance being addition to params above\nfor tag lib if you already have data this is what it is expecting to be sent to it

\n
<map:lookup \n   showState="${false}"   \n   showArea="${false}" \n   showLatLong="${false}" \n   streetRequired="${false}"\n   instance="${[\n        countrysearch:'',\n        countryCode:'',\n        postcode:'',\n        building:'',\n        street:'',\n        city:'',\n        state:'',\n        communitySearch:'',\n        latitude:'',\n        longitude:'',\n    ]}"\n  />\n<!-- similar example with some data already set all of below\n is enough to trigger maps / overlay - could be saved data -->\n<map:lookup\n    showState="${false}"\n    showArea="${false}"\n    showLatLong="${false}"\n    streetRequired="${false}"\n    instance="${[\n        countrysearch:'United Kingdom',\n        countryCode:'UK',\n        postcode:'SE1 1AP',\n        building:'',\n        street:'',\n        city:'',\n        state:'',\n        communitySearch:'Southwark',\n        latitude:'51.5017828',\n        longitude:'-0.09326659999999999',\n    ]}"\n/>\n
\n

Map overlay editor : http://localhost:8080/map

\n

This provides an interface to edit and modify existing kml boundaries on the fly.\nIt provides raw kml extracted file, has feature to upload, hasn't been tested.

\n

Instructions / Notes

\n

Customising your own lookup

\n

You will need to take a copy of _address.gsp when verifyCode is called the data object returned contains full dump of\neverything useful .

\n

console.log(JSON.stringify(data)) will show all but 2 full data sets: data.latLongDetails and data.fullPostCodeDetails

\n

KML Notes :

\n
    \n
  1. /opt/kmlplugin/_map/KML/ ->
  2. \n
\n

Place a file for the given country. This will be KML file you get hold of that contains typically all the official boroughs/councils of a given country in the case of UK we found:

\n

was here\nSite appears to no longer work. You can get hold of file from here

\n

This file was then stored in this folder as

\n

_default.kml

\n

/opt/kmlplugin/_map/KML/_default.kml

\n

To parse KML Files Add this to BootStrap.groovy

\n
 KmlHelper.parseKml()\n
\n

When the site starts up for the very first time, it will attempt to read through this file and inside the same folder it will expand out all the found boroughs.

\n
$ ls -rtml /opt/kmlplugin/_map/KML/|more\ntotal 9876\n-rw-rw-r-- 1 mx1 mx1 7394653 Nov 29 17:08 _default.kml\n-rw-rw-r-- 1 mx1 mx1   19199 Dec  1 19:36 BEDFORDSHIRE.kml\n-rw-rw-r-- 1 mx1 mx1   31337 Dec  1 19:36 BUCKINGHAMSHIRE.kml\n-rw-rw-r-- 1 mx1 mx1   24338 Dec  1 19:36 CAMBRIDGESHIRE.kml\n-rw-rw-r-- 1 mx1 mx1     584 Dec  1 19:36 CHESHIRE.kml\n-rw-rw-r-- 1 mx1 mx1     584 Dec  1 19:36 CORNWALL.kml\n-rw-rw-r-- 1 mx1 mx1     582 Dec  1 19:36 CUMBRIA.kml\n
\n

At this point it has loaded up each borough and also split each borough/community into its own specific file.

\n

This process happens only once and can be redone by clearing out and dropping in as above a _default.kml file.

\n

This triggers an internal process to do what has been demonstrated.

\n

Once it has been generated. The site will from there on refer to all created files to load up each community.

\n

This means you can now edit each of the generated files for a given community and re-save it \ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd a saved version and application restart will then ensure the site is using whatever latest content each community has.

\n

Upon start up you will need to visit the map regions and it will show what has been produced.

\n

To enable logging:

\n

Add below to grails-app/conf/logback.groovy

\n
    logger('org.grails.plugins.kml', ERROR, ['STDOUT'], false)\n    logger('org.grails.plugins.kml', DEBUG, ['STDOUT'], false)\n    logger('org.grails.plugins.kml', WARN, ['STDOUT'], false)\n    logger('org.grails.plugins.kml', INFO, ['STDOUT'], false)\n
\n

##Credits

\n

/map KML Editor taken from Kjell Scharning

\n

KML Map editor or /map segement is thanks to above link which gave the source to build the rest as such.\nHis worked got wired into what the rest of the code does, as per what his page expected.

\n

/lookup my own work over different projects / requirements.

\n
Please note - KML Parsing utiltiy. I put this class together as an expansion from this question on SO extract-coordinates-from-kml-file-in-java. Since this plugin is currently functional with provided kml file, any one who has additional time and wishes to come on board and improve KML Parsing to work with other standards or any other aspect of this plugin, I be happy to accept their input. This isn't something I'm currently using and was put together for another project, decided to release into public realm since I guess it is a bit of magic.
\n

\"sample\n\"sample\n\"sample\n\"sample\n\"sample\n\"sample\n\"sample\n\"sample\n\"sample\n\"sample\n\"sample

\n" }, { "bintrayPackage": { "name": "ldap-server", "repo": "plugins", "owner": "grails", "desc": "Grails LDAP Server Plugin", "labels": [ "ldap" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/bobbywarner/grails-ldap-server/issues", "latestVersion": "1.0.0", "updated": "2016-04-01T15:38:25.762Z", "systemIds": [ "org.grails.plugins:ldap-server" ], "vcsUrl": "https://github.com/bobbywarner/grails-ldap-server" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": null }, { "bintrayPackage": { "name": "less-asset-pipeline", "repo": "asset-pipeline", "owner": "bertramlabs", "desc": "LESS Compiler for the Asset-Pipeline", "labels": [ "asset-pipeline", "less", "css" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/bertramdev/less-asset-pipeline/issues", "latestVersion": "5.0.1", "updated": "2024-09-13T18:26:48.000Z", "systemIds": [ "com.bertramlabs.plugins:less-asset-pipeline" ], "vcsUrl": "https://github.com/bertramdev/less-asset-pipeline" }, "documentationUrl": null, "mavenMetadataUrl": "https://repo1.maven.org/maven2/com/bertramlabs/plugins/less-asset-pipeline/maven-metadata.xml", "readme": "

LESS Asset Pipeline

\n

MOVED: This project has moved to a sub project of the main asset-pipeline repository http://github.com/bertramdev/asset-pipeline

\n

The less-asset-pipeline is a plugin that provides LESS support for the asset-pipeline static asset management plugin.

\n

For more information on how to use asset-pipeline, visit here.

\n

Installation

\n

Add this plugin to your classpath in gradle or dependencies list depending on how you are using it:

\n
//Example build.gradle file\nbuildscript {\n    repositories {\n        mavenCentral()\n    }\n    dependencies {\n        classpath 'com.bertramlabs.plugins:asset-pipeline-gradle:2.5.4'\n        classpath 'com.bertramlabs.plugins:less-asset-pipeline:2.5.4'\n    }\n}\n
\n

Usage

\n

Create files in your standard assets/stylesheets folder with extension .less or .css.less. You also may require other files by using the following requires syntax at the top of each file or the standard LESS import:

\n
/*\n*= require test\n*= require_self\n*= require_tree .\n*/\n\n/*Or use this*/\n@import 'test'\n\n
\n

Less4j Support

\n

This plugin now defaults to compiling your less files with less4j instead of the standard less compiler. To Turn this off you must adjust your config:

\n
assets {\n    configOptions = [\n      less: [\n        compiler: 'standard'\n      ]\n    ]\n}\n
\n

Production

\n

During war build your less files are compiled into css files. This is all well and good but sometimes you dont want each individual less file compiled, but rather your main base less file. It may be best to add a sub folder for those LESS files and exclude it in your precompile config...

\n

Sample Gradle Config:

\n
  assets {\n      excludes = ['mixins/*.less']\n  }\n
\n" }, { "bintrayPackage": { "name": "lightningj-grails", "repo": "plugins", "owner": "herrvendil", "desc": "Grails 3.x Plugin to integrate LightningJ into a Grails application.", "labels": [ "lightning" ], "licenses": [ "LGPL-3.0" ], "issueTrackerUrl": "https://github.com/lightningj-org/lightningj-grails/issues", "latestVersion": "0.5.2-Beta", "updated": "2019-02-07T18:38:29.311Z", "systemIds": [ "org.lightningj:lightningj-grails" ], "vcsUrl": "https://github.com/lightningj-org/lightningj-grails" }, "documentationUrl": "https://lightningj-org.github.io/lightningj-grails/", "mavenMetadataUrl": null, "readme": "

Readme for LightningJ Grails Plugin

\n

LightningJ Grails plugin is a project to simplify the usage of the LightningJ\nlibrary in Grails 3.3.x applications and above.

\n

For documentation see docs/index.adoc of the project web-site at\nhttp://grails.lightningj.org

\n

Build status Master branch: \"Build

\n" }, { "bintrayPackage": { "name": "mail", "repo": "plugins", "owner": "grails", "desc": "Grails mail plugin", "labels": [ "mail" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails3-plugins/mail/issues", "latestVersion": "3.0.0", "updated": "2019-10-22T14:59:33.694Z", "systemIds": [ "org.grails.plugins:mail" ], "vcsUrl": "https://github.com/grails3-plugins/mail" }, "documentationUrl": "https://grails3-plugins.github.io/mail/", "mavenMetadataUrl": null, "readme": "

The Grails mail plugin provides a convenient DSL for sending email. It supports plain text, html, attachments, inline resources and i18n among other features.\n\"Build

\n

Mail can be sent using the @mailService@ via the @sendMail@ method. Here is an example\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd

\n
mailService.sendMail {\n   to "fred@gmail.com","ginger@gmail.com"\n   from "john@gmail.com"\n   cc "marge@gmail.com", "ed@gmail.com"\n   bcc "joe@gmail.com"\n   subject "Hello John"\n   text 'this is some text'\n}\n
\n

Please see the User Guide for more information.

\n

The plugin is released under the Apache License 2.0 and is produced under the Grails Plugin Collective.

\n

Versions

\n\n

Issues

\n

Issues can be raised via GitHub Issues.

\n

Contributing

\n

Pull requests are the preferred method for submitting contributions. Please open an issue via that issue tracker link above and create an issue describing what your contribution addresses.

\n

If you are contributing documentation, raising an issue is not necessary.

\n" }, { "bintrayPackage": { "name": "mailinglist", "repo": "maven", "owner": "vahid", "desc": "mailinglist is a Grails plugin which makes use of quartz to dynamically schedule either group or specific email address contact. You create html email templates with images etc, then define time and date for this to be sent. The job is then added to quartz and set to email at given time. The queue can easily be controlled via bootstrap so that nothing is ever lost.\r\n\r\nDo you want to email a person at 11:41 pm or maybe a group of people at 2.15am? then look no further.\r\n\r\nYou can schedule an email to be scheduled and to run on a set date and time.\r\n\r\nSupports HTML emails with inline images as well as attachments has been tested on outlook and result appears to load fine.", "labels": [ "mail" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/vahidhedayati/mailinglist/issues", "latestVersion": "3.0.3", "updated": "2017-02-18T12:05:20.775Z", "systemIds": [ "org.grails.plugins:mailinglist" ], "vcsUrl": "https://github.com/vahidhedayati/mailinglist" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

mailinglist 0.34

\n

mailinglist is a Grails plugin which makes use of quartz to dynamically schedule either group or specific email address contact.\nYou create html email templates with images etc, then define time and date for this to be sent. The job is then added to quartz and set to email at given time.\nThe queue can easily be controlled via bootstrap so that nothing is ever lost.

\n

Do you want to email a person at 11:41 pm or maybe a group of people at 2.15am? then look no further.

\n

You can schedule an email to be scheduled and to run on a set date and time.

\n

Supports HTML emails with inline images as well as attachments has been tested on outlook and result appears to load fine.

\n

For a walk through guide on how to install this plugin goto : https://github.com/vahidhedayati/ml-test

\n

Installation for grails 2.4+ assets based sites:

\n

Add plugin Dependency in BuildConfig.groovy :

\n
compile ":mailinglist:0.34"\n
\n

Installation for grails 3+

\n
compile "org.grails.plugins:mailinglist:3.0.4"\n
\n

For grails 3 You will need to add bootstrap-datetimepicker.min.js to your grails-app/js/javascripts folder

\n

The file can be found here:

\n

https://github.com/vahidhedayati/mailinglist/tree/master/src/main/templates/js or https://tarruda.github.io/bootstrap-datetimepicker/

\n

Under 2.4.0 you may need to review hibernate version and update to:

\n
runtime ":hibernate4:4.3.5.4"\n
\n

Please refer to example site grails 2:

\n

Please refer to example site grails 3:

\n

Installation for grails < 2.4 based resources sites 2.X -> 2.3.X

\n

Under Resources based application you can still use the latest code base, but you need to exclude hibernate. Something like this:

\n
compile (":maillinglist:X.XX") { excludes 'hibernate' }\n
\n

If you wish you could also use the very last build under compatible hibernate version built under resources:\nAdd plugin Dependency in BuildConfig.groovy :

\n
compile ":mailinglist:0.19"\n
\n

Since 0.23 you also require:

\n

In the latest app I had to also enable fixes for export plugin, unsure why it did not pull it from within plugin...

\n

Under BuildConfig.groovy:

\n
\trepositories {\n\t\t......\n\t\tmavenRepo "http://repo.grails.org/grails/core"\n    \t}\n\n    \tdependencies {\n\t\t.....\n\t\tcompile 'commons-beanutils:commons-beanutils:1.8.3'\n    \t}\n
\n

The two extra lines one to repositories and one to dependencies.

\n

Resources based sites : (Grails pre 2.4 ) grails-app/layouts/main.gsp update:

\n
jquery, jquery-ui libraries:
\n

your layouts main.gsp: (add jquery-ui and jquery - or add them into ApplicationResources.groovy and ensure you refer to it in your main.gsp or relevant file

\n
\t<g:javascript library="jquery"/>\n\t<g:javascript library="jquery-ui"/>\n\t\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\n\t\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\n\t<g:layoutHead/>\n\t<mailinglist:loadbootstrap/>\n</head>\n
\n

You will also notice mailinglist:loadbootstrap/ this loads up bootstrap to make modalbox work - if you already have bootstrap then change this to

\n
<mailinglist:loadplugincss/>\n
\n

I have found using this method of calling bootstrap within one of my projects to have caused a problem when looking at source it was loading before jquery,\nso by moving this block further below end head tag resolved the issue.

\n

Assets based sites : (Grails 2.4+ ) grails-app/layouts/main.gsp update:

\n

A default site just add the mailingList line below application.js to grails-app/layouts/main.gsp

\n
\t<asset:stylesheet src="application.css"/>\n        <asset:javascript src="application.js"/>\n        <mailinglist:loadbootstrap/>\n
\n

Or if you already have bootstrap initialised :

\n
\t<mailinglist:loadplugincss/>\n
\n

replace the loadboostrap to loadplugincss

\n

Now with that all in place open grails console or from the command line run

\n
grails mlsetup org.example.com 5\n
\n

Where org.example.com is your package and 5 is the amount of dynamic schedule jobs to generate,

\n

Assuming package was labelled as above org.example.com and schedule jobs as 5, install script will create

\n
\nViews \t\tunder views/mailingList/_addedby.gsp\n\nJobs under \torg.example.com/ScheduleEmail0Job.groovy\n\t\t   \torg.example.com/ScheduleEmail1Job.groovy\n\t\t   \torg.example.com/ScheduleEmail2Job.groovy\n\t\t   \torg.example.com/ScheduleEmail3Job.groovy\n\t\t   \torg.example.com/ScheduleEmail4Job.groovy\n\nServices \tunder org.example.com\n\t\t\tIt will update QuartzEmailCheckerService to only schedule physical jobs ScheduleEmail[0-4]Job\n
\n

The domains generated in your application extend base domains within plugin, besides this the rest of the controllers etc are pushed to your own application for you to do what you like with it.

\n

i18n support

\n

From 1.17 you can configure your i18n/messages_{locale}.properties to include translations for terms used within this plugin, to get the latest running terms for translation please refer to the wiki

\n

Version changes

\n
0.34 @idiengaid identified issue with bulk emails and templates, earlier work from 0.32 needed additional if check around template\n0.33 @idiengaid spotted instance with missing i\n0.32 Pull request https://github.com/vahidhedayati/mailinglist/pull/5 \n\nmartofeld added some commits 5 hours ago\n @martofeld\tAdd support for using templates in the mail\t\t\t5495ef2\n @martofeld\tAvoid parsing if values are already a List + fix typo\t\t\ted30889\n @martofeld\tMissed some implementations of the new template\t\t\ta3a5601\n \n \n0.31 #3 Improvement of the mlsetup script and produced services \n\tIf you have refreshed mlsetup script as part of 0.30, its worth doing it again. This will produce tidier services.\n0.30 #3 further tidyup of cron expression rule checking\n0.29 #3 Cron expressions introduced so either send via cron schedule or specify date time\n0.28 minor change update modaldynamix to 0.28  and pluginbuddy 0.3 \n0.27 minor change update to modaldynamix ver 0.27\n0.26 Updated to 2.4.2, cleaned up end user app verification by using pluginbuddy. \n0.25 latest modaldynamix called - pop up boxes loading correctly according to screen size\n0.24 Fixed datetime issue under assets based sites.\n0.23 Latest modaldynamix plugin version used - modalboxes resized according to requirement - colour added to modalbox button callers.\n0.22 Excess css entries removed from MailingList.css - causing larger buttons and unnessary spacing issues.\n0.21 Missing jquery-ui js file manually inserted in for assets based sites.\n0.20 Release of assets version - identical to 0.19 but hibernate bumped to match assets based sites.\n0.19 last release for resources based sites. to keep upto date update your underlying site to assets\n0.18 i18n support added to services - further tidy up of contact a person page.\n0.17 Tidy up of mailSent view on main menu, added i18n support to most of the calls.\n0.16 latest ckeditor added\n0.15 mailinglist.warn.duplicate and mailinglist.warn.period added, issue with search mailingList fixed. Duplicate email warnings to same contactGroup  set to show on preview screen\n0.14 fixed pagination / export features on mailinglist page.\n0.13 issue with list - export feature was not working - format was not being passed - format now set to extension params\n0.12 Changed ckeditor to 4.4.0.0-SNAPSHOT http://jira.grails.org/browse/GPCKEDITOR-40\n0.11 Removal of non thread safe calls within QuartsStatusService ret_triggerName ret_triggerGroup ret_jobName, now returned as  map and parsed as params back in modSchedule\n0.10 more tidying up fixes to minor broken calls\n0.9 tidyup to taglib/service and gsps \n0.8 minor changes to _list1-top.gsp - called correct controller to display more information on scheduled jobs\n0.7 updates to default db table names, readme updates, correct ckeditor call for in index.gsp, giving upload feature for images \n0.6 minor fix MailingList controller save wrong parameter for categories\n0.5 minor fix gsp listing wrong domainClass in mailingList/_form.gsp\n0.4 moved out all of the manual modalbox calls and called modaldynamix plugin \n0.3 Missing images, alerts left in java scripts tut tut, contactclients gsp page had lots of bugs now fixed, scheduling looks a lot healthier.\n0.2 moved most back into actual plugin - bug with existing used schedule issues whilst attempting to schedule something for now whilst others queued.\n0.1 release - nearly everything written to clients project\n
\n

Config.groovy changes

\n

Required Config.groovy configurations:

\n
/*\n * Optional values to override DB table names for this plugin:\n * mailinglist.table.attachments='mailing_list_attachments'\n * mailinglist.table.categories='categories'\n * mailinglist.table.mailinglist='mailing_list'\n * mailinglist.table.schedule='mailing_list_schedule'\n * mailinglist.table.senders='mailing_list_senders'\n * mailinglist.table.templates='mailing_list_templates'\n * These options define if there should be a warning to confirm an email was sent to same group within defined period\n * mailinglist.warn.duplicate='Y'\n * --- Periods are:  | H for Hours | D for days | M for minutes | m for months | y for years | \n * mailinglist.warn.period='2H'\n * These are all the local tables created that in turn extend domainClasses from this plugin.\n * Check out your domainClass folder under the package you provided after you run the mlsetup command.\n */\n \n\t\n// Your date format that matches input of jquery datepicker config \n//mailinglist.dtFormat='dd/MM/yyyy HH.mm'\n\n\nckeditor {\n\t//config = "/js/myckconfig.js"\n\tskipAllowedItemsCheck = false\n\tdefaultFileBrowser = "ofm"\n\tupload {\n\t\n\t\t// basedir = "/uploads/"\n\t\t\n\t\tbaseurl="${grails.baseURL}"+'/uploads/'\n\t\tbasedir = "${externalUploadPath}"\n\t\t\n\t\t\toverwrite = false\n\t\t\tlink {\n\t\t\t\tbrowser = true\n\t\t\t\tupload = false\n\t\t\t\tallowed = []\n\t\t\t\tdenied = ['html', 'htm', 'php', 'php2', 'php3', 'php4', 'php5',\n\t\t\t\t\t\t\t  'phtml', 'pwml', 'inc', 'asp', 'aspx', 'ascx', 'jsp',\n\t\t\t\t\t\t  'cfm', 'cfc', 'pl', 'bat', 'exe', 'com', 'dll', 'vbs', 'js', 'reg',\n\t\t\t\t\t\t  'cgi', 'htaccess', 'asis', 'sh', 'shtml', 'shtm', 'phtm']\n\t\t\t}\n\t\t\timage {\n\t\t\t\tbrowser = true\n\t\t\t\tupload = true\n\t\t\t\tallowed = ['jpg', 'gif', 'jpeg', 'png']\n\t\t\t\tdenied = []\n\t\t\t}\n\t\t\tflash {\n\t\t\t\tbrowser = false\n\t\t\t\tupload = false\n\t\t\t\tallowed = ['swf']\n\t\t\t\tdenied = []\n\t\t\t}\n\t}\n}\n\njqueryDateTimePicker {\n\tformat {\n\t\tjava {\n\t\t\tdatetime = "dd/MM/yyyy HH.mm"\n\t\t\tdate = "dd/MM/yyyy"\n\t\t}\n\t\tpicker {\n\t\t\tdate = "'dd/mm/yy'"\n\t\t\ttime = "'H.mm'"\n\t\t}\n\t}\n}\n\ngrails.mime.types = [ html: ['text/html','application/xhtml+xml'],\n\txml: ['text/xml', 'application/xml'],\n\ttext: 'text-plain',\n\tjs: 'text/javascript',\n\trss: 'application/rss+xml',\n\tatom: 'application/atom+xml',\n\tcss: 'text/css',\n\tcsv: 'text/csv',\n\tpdf: 'application/pdf',\n\trtf: 'application/rtf',\n\texcel: 'application/vnd.ms-excel',\n\tods: 'application/vnd.oasis.opendocument.spreadsheet',\n\tall: '*/*',\n\tjson: ['application/json','text/json'],\n\tform: 'application/x-www-form-urlencoded',\n\tmultipartForm: 'multipart/form-data'\n  ]\n
\n

You will notice grails.baseURL externalUploadPath within ckeditor, this was done to externalise image uploads so upon a redployment the images were still available, the approach I took to this was to run values from setenv.sh within tomcat and pass this values in as variables into Config.groovy as per below:

\n

// configuration for plugin testing - will not be included in the plugin zip

\n

// In my tomcat setenv.sh

\n
//UPLOADLOC="$CATALINA_HOME/uploads"\n//JAVA_OPTS="$JAVA_OPTS -DUPLOADLOC=$UPLOADLOC"\n//HOSTNAME=$(hostname)\n//JAVA_OPTS="$JAVA_OPTS -DSERVERURL=$HOSTNAME"\n
\n

Produces running tomcat with the following values:

\n
// -DUPLOADLOC=/opt/tomcat7/tc1/uploads\n// -DSERVERURL=my.server.com\n
\n

In my Config.groovy at the top I have this

\n
if (System.getProperty('UPLOADLOC')) {\n\texternalUploadPath=System.getProperty('UPLOADLOC')+File.separator\n}\nif (System.getProperty('SERVERURL')) {\n\tgrails.baseURL='http://'+System.getProperty('SERVERURL')\n} else{\n\tgrails.baseURL='http://localhost'\n}\n
\n

Now those values are valid within the ckeditor configuration

\n

Boostrap changes

\n

An example BootStrap call to requeue outstanding or interuppted schedules is to add something like this :

\n
import grails.plugin.mailinglist.core.ScheduleBase\n\nclass BootStrap {\n\tdef mailingListEmailService\n    def init = { servletContext ->\n\t\tdef getEmails = ScheduleBase.findAllByScheduleCompleteAndScheduleCancelled(false,false)\n\t\tgetEmails.each { params ->\n\t\t\tif (params.dateTime && params.emailMessage) {\n\t\t\t\tprintln "RESCHEDULING MAIL QUEUE ${params?.id} --       ${params?.mailFrom}---${params?.recipientToGroup}--${params?.recipientToList}"\n\t\t\t\tmailingListEmailService.rescheduleit(params)\n\t\t\t}\n\t\t}\n\t}\n}\n\n
\n

addedby within forms

\n

There is a field passed around through the application and by default it is blank, this is due to a file called views/mailingList/_addedby.gsp

\n

Take a look at this, if your existing application has some form of user and current user is being returned via session or another method i.e. params or something then update this page to refer to this value.\nThis should fix the issue all around the site, no guarantee haha.

\n

conf/UrlMappings.groovy & plugin default holding page

\n

If this plugin is the only purpose of your site, then simply update your url mappings to point to the holding page of this plugin:

\n
"/" {\n\tcontroller = "MailingList"\n\taction = "index"\n}\n// Commented out default and put in above\n//"/"(view:"/index")\n
\n

The plugin has a menu which can be found under: http://yoursite:8080/mailinglist/MailingList

\n

This is the main menu, the two core options on the top left hand side, Email a person and contact clients.

\n

\"mailinglist

\n

The rest of the menu are the manual methods of reviewing email list, or removing attachments etc.

\n

\"Email\nThis is what to expect when emailing a person

\n

\"Configure\nThe now button defaults to now, other than that choose actual date time you wish to email this person.

\n

\"When\nIt will just sit in that queue you can stop the job or force it play now from that same scheduling menu.

\n

\"Contacting\nThis is the look and feel of contact group, subject is the only thing defined, everything else is clickable or uploadable. At the top are some green buttons, each one will update this form dynamically.

\n

\"New\nAdding a new template, if you do not have a preset template to use for sending emails then create a new one from the first green button at the top of the page.

\n

\"Attach\nThis is if you wish to attach files like documents to be sent with email.

\n

\"After\nAttachments run in iframes, so for changes to take effect on main form you need to use the close button on the top of the page.

\n

\"Upload\nCSV Uploader which will be your group of users to contact, please note it will always miss out on the first line since on exports usually the first line is the field name

\n

\"Add\nThe senders from group emails come from the Senders DB table, so you need to register it once set it should remain for reuse on next use.

\n

\"Schedule\nSet the time you wish to email to this group, you have now selected and ticked everything else including once template was uploaded you clicked the select box to choose it which then popped open your presaved template.

\n

\"Preview\nSince emailing a group of people usually requires more care, there has been a preview screen added to ensure you are happy with what is being done. if so click confirm sending email otherwise click edit to go back,

\n

\"Schedule\nThis now contains our previous job which is set in a few hours plus our new job for now, we will now choose Completed schedules from the drop down to see:

\n

\"Completed\nThis group email as completed

\n

\"Mail\nThis is my email log confirming it sent an email from set email to the uploaded csv which had 3 gmail emails, it bounced cos my sendmail is not configured and just as well considering the amount of junk I been sending haha

\n

#Common Issues:\nAfter attempting to run

\n
mlsetup org.example.com 5\n
\n

you must referesh the project and run

\n
grails refresh-dependencies\n
\n

If your in ggts you may still see red asterix you can run:

\n
grails clean \n
\n

These are the manual command lines goto project right click grails tools, grails command wizard will help you with those or actual command prompt below just drop the grails in front of all of the above.

\n

Date Format: Trying to schedule and can not ?

\n
dd/MM/yyyy HH.mm\n
\n

You may see this :

\n
Could not queue job please check quartz queue to ensure schedule slots are free\n
\n

If you look at the console logs you will see it could not parse and it shows a date and time, look closely at the time you will find it has a : seperating the hour and mins.\nI know I should have set this as the default right :) This is the defaults sadly so please review main config and ensure your jquery date time config is set properly to match what is needed:

\n
mailinglist.dtFormat='dd/MM/yyyy HH.mm'\njqueryDateTimePicker {\n\tformat {\n\t\tjava {\n\t\t\tdatetime = "dd/MM/yyyy HH.mm"\n\t\t\tdate = "dd/MM/yyyy"\n\t\t}\n\t\tpicker {\n\t\t\tdate = "'dd/mm/yy'"\n\t\t\ttime = "'H.mm'"\n\t\t}\n\t}\n}\n
\n

This is in the main config above, but worth a remention, so if you want to set a different input type for date time,\nthen define this value in your config to match aboves config to get around the standard config which is a dot seperating hours and minutes.

\n
mailinglist.dtFormat='dd/MM/yyyy HH.mm'\t\n
\n

Ensure all of above tallies up for it all work properly

\n

Pop up Modal boxes within contact clients

\n

Take a look at https://github.com/vahidhedayati/modaldynamix follow the guide then refer to pages within this plugin to get a better idea on how to use it all together.

\n

Finally

\n

A big thank you as always to Burt Beckwith for cleaning up the code:\nUnfortunately due to issues with merging repo was cleaned up, original code cna be found here:\nThose changes are here: https://github.com/burtbeckwith/mailinglist/

\n

@martofeld martin For adding template support to the plugin

\n

Sergey Ponomarev For cleaning up and adding formating to the README.md

\n

Thank you all for you contributions. If you wish to contribute or add stuff I be happy to add you as a project member. I am no longer using this project so will not be getting much updates from me.

\n" }, { "comment": "Micronaut is part of Grails since 4.0.0. Is this entry still relevant?", "bintrayPackage": { "name": "micronaut-beans", "repo": "plugins", "owner": "grails", "desc": "Grails Plugin For Adding Micronaut Beans To The Spring Application Context", "labels": [ "micronaut" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails-plugins/micronaut-beans/issues", "latestVersion": "1.0.0.M2", "updated": "2018-08-10T16:58:48.114Z", "systemIds": [ "org.grails.plugins:micronaut-beans" ], "vcsUrl": "https://github.com/grails-plugins/micronaut-beans" }, "documentationUrl": "https://grails-plugins.github.io/micronaut-beans/", "mavenMetadataUrl": null, "readme": "https://grails-plugins.github.io/micronaut-beans/" }, { "bintrayPackage": { "name": "middleware", "repo": "plugins", "owner": "lduarte", "desc": "Grails middleware plugin", "labels": [ "middleware" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/driverpt/grails-middleware/issues", "latestVersion": "0.0.3", "updated": "2016-03-31T13:31:54.765Z", "systemIds": [ "org.grails.plugins:middleware" ], "vcsUrl": "https://github.com/driverpt/grails-middleware" }, "documentationUrl": "https://driverpt.github.io/grails-middleware/latest", "mavenMetadataUrl": null, "readme": "

\"Build

\n

Grails Middleware Plugin

\n

See documentation for further information.

\n" }, { "bintrayPackage": { "name": "modninfobip", "repo": "plugins-libraries", "owner": "modnsolutions", "desc": "Infobip SMS Grails plugin", "labels": [ "infobip", "sms" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/osaetinevbuoma/modninfobip/issues", "latestVersion": "1.0.2", "updated": "2016-08-31T14:10:51.013Z", "systemIds": [ "com.modnsolutions:modninfobip", "org.grails.plugins:modninfobip" ], "vcsUrl": "https://github.com/osaetinevbuoma/modninfobip" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Infobip plugin \"Build

\n

Grails plugin for Infobip SMS API

\n

Prerequisite to using modninfobip plugin

\n\n

Method Declarations

\n

Generate basic authorization

\n
String basicAuthorization(String username, String password)\n
\n\n

NB: Basic authorization is mandatory for all infobip REST API requests.

\n

Send an SMS to a single phone number

\n
JSONObject sendSingleMessage(String authorization, String from, String to, String text)\n
\n\n

Send an SMS to multiple phone numbers

\n
JSONObject sendSingleMessage(String authorization, String from, List to, String text)\n
\n\n

Send multiple SMS's to multiple or same recipient phone number

\n
JSONObject sendMultipleMessages(String authorization, JSONObject data)\n
\n\n
{  \n   "messages":[  \n      {  \n         "from":"InfoSMS",\n         "to":[  \n            "41793026727",\n            "41793026731"\n         ],\n         "text":"May the Force be with you!"\n      },\n      {  \n         "from":"41793026700",\n         "to":"41793026785",\n         "text":"A long time ago, in a galaxy far, far away... It is a period of civil war. Rebel spaceships, striking from a hidden base, have won their first victory against the evil Galactic Empire."\n      }\n   ]\n}\n
\n

Get delivery reports

\n
JSONObject deliveryReport(String authorization)\n
\n

Get filtered delivery reports

\n
JSONObject deliveryReport(String authorization, Map filters)\n
\n\n

NB: Delivery reports can only be gotten once. A second call returns an empty result.

\n

Pull received messages to phone number from Infobip server

\n
JSONObject pullReceivedMessages(String authorization)\nJSONObject pullReceivedMessages(String authorization, int limit)\n
\n\n

Get logs

\n
// Call the messageLog method of corresponding service \n// class (SendMessageService or ReceiveMessageService)\nJSONObject messageLog(String authorization)\n
\n

Get filtered logs

\n
// Call the messageLog method of corresponding service \n// class (SendMessageService or ReceiveMessageService)\nJSONObject messageLog(String authorization, Map filters)\n
\n\n

Check Account Balance

\n
JSONObject checkAccountBalance(String authorization)\n
\n

Installation

\n

Edit application.groovy (or application.yml if you prefer) and build.gradle

\n\n
infobip.host = "https://api.infobip.com/sms/1"\n
\n

OR

\n\n
infobip:\n    host: https://api.infobip.com/sms/1\n
\n\n
repositories {\n    maven {\n        url  "http://dl.bintray.com/modnsolutions/plugins-libraries" \n    }\n}\n\ndependencies {\n    compile "org.grails.plugins:modninfobip:1.0.2"\n}\n
\n

Usage

\n\n
import com.modnsolutions.ReceiveMessageService //service to pull received messages and message log from infobip server\nimport com.modnsolutions.SendMessageService // service to send messages via infobip, get delivery report and message logs\nimport com.modnsolutions.UtilitiesService\n
\n\n
ReceiveMessageService receiveMessageService\nSendMessageService sendMessageService\nUtilitiesService utilitiesService\n
\n\n
String basicAuthorization = utilitiesService.basicAuthorization("INFOBIP_USERNAME", "INFOBIP_PASSWORD")\nJSONObject singleMessageResponse = sendMessageService.sendSingleMessage(basicAuthorization, from, to, text)\nprintln singleMessageResponse\n
\n

Example

\n
import com.modnsolutions.ReceiveMessageService\nimport com.modnsolutions.SendMessageService\nimport com.modnsolutions.UtilitiesService\n\n// In Grails you can handle json objects and arrays by importing and using\n// import org.grails.web.json.JSONArray\n// import org.grails.web.json.JSONObject\n\nclass SMSController {\n    ReceiveMessageService receiveMessageService\n    SendMessageService sendMessageService\n    UtilitiesService utilitiesService\n    \n    def sendSingleSMS(String from, String to, String text) {\n        String basicAuthorization = utilitiesService.basicAuthorization("INFOBIP_USERNAME", "INFORBIP_PASSWORD")\n        render sendMessageService.sendSingleMessage(basicAuthorization, from, to, text)\n    }\n    \n    def pullMessages() {\n        String basicAuthorization = utilitiesService.basicAuthorization("INFOBIP_USERNAME", "INFORBIP_PASSWORD")\n        render receiveMessageService.pullReceivedMessages(basicAuthorization)\n    }\n    \n    def checkAccountBalance() {\n        String basicAuthorization = utilitiesService.basicAuthorization("INFOBIP_USERNAME", "INFORBIP_PASSWORD")\n        render utilitiesService.checkAccountBalance(basicAuthorization)\n    }\n    \n    ...\n}\n
\n" }, { "bintrayPackage": { "name": "mongodb", "repo": "plugins", "owner": "grails", "desc": "GORM for MongoDB", "labels": [ "gorm", "mongodb" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails/gorm-mongodb/issues", "latestVersion": "8.2.0", "updated": "2024-03-15T19:26:14.000Z", "systemIds": [ "org.grails.plugins:mongodb" ], "vcsUrl": "https://github.com/grails/gorm-mongodb" }, "documentationUrl": null, "mavenMetadataUrl": "https://repo1.maven.org/maven2/org/grails/plugins/mongodb/maven-metadata.xml", "readme": "

\"Java\n\"Release\"

\n

GORM for MongoDB

\n

This project implements GORM for the MongoDB Document Database.

\n

NOTE: This source code here is for version 6.x and above. For prevoius versions' source see the relevant branch on the Grails Data Mapping project.

\n

For more information see the following links:

\n\n

For the current development version see the following links:

\n\n" }, { "bintrayPackage": { "name": "mongogee", "repo": "plugins", "owner": "ikalizpet", "desc": "Mongogee is a Grails plugin for MongoDB data migration management", "labels": [ "migration", "mongodb" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/ikaliZpet/mongogee/issues", "latestVersion": "0.9.4", "updated": "2018-01-04T18:58:41.518Z", "systemIds": [ "org.grails.plugins:mongogee" ], "vcsUrl": "https://github.com/ikaliZpet/mongogee" }, "documentationUrl": "https://binlecode.github.io/grails-mongogee/", "mavenMetadataUrl": null, "readme": "

mongogee

\n

MongoDB data migration Grails Plugin.

\n

TravisCI \"Build

\n

INTRODUCTION

\n

Mongogee Grails plugin is a simple, secure service for mongodb data migration management.\nThis plugin is inspired by Mongobee (https://github.com/mongobee/mongobee) MongoDB data migration toolset.

\n

All the credits of the annotation based migration change management logic go to the Mongobee authors.

\n

This repository contains source code of Mongogee, and a testing sample host Grails application.

\n

INSTALL

\n

In host Grails application's build.gradle file:

\n
plugins {\n\tcompile ':mongogee:$version'\n}\n
\n

PREREQUISITES

\n

Hosting Grails application version 3.0+.

\n

CONFIGURATION

\n

In host Grails application grails-app/conf/application.yml

\n
mongogee:\n    changeEnabled: true \t\t          # default is true\n    continueWithError: false \t          # default is false\n    changeLogsScanPackage: 'some.package' # required, no default value\n    lockingRetryEnabled: false            # default to true\n    lockingRetryIntervalMillis: 3000      # default to 5s\n    lockingRetryMax: 60                   # default to 120, aka 10min\n
\n

WRITE MIGRATION CHANGES

\n

Adopting and extending Mongobee (https://github.com/mongobee/mongobee) annotations. There are two level of migration change units: change-logs (class level) and change-sets (method level).\nChange-logs can be written in either Java or Groovy. Some groovy examples are below:

\n
@ChangeLog(order = '001')\n\tclass MongogeeTestChangeLog {\n\t\n\t    @ChangeSet(author = "testuserA", id = "test1", order = "01")\n\t    void testChangeSet1() {\n\t        System.out.println("invoked 1")\n\t    }\n\t\n\t    @ChangeSet(author = "testuserB", id = "test2", order = "02")\n\t    void testChangeSet2(DB db) {\n\t        System.out.println("invoked 2 with mongodb DB argument: $db")\n\t    }\n\t\n\t    @ChangeSet(author = 'testuser', id = 'test3', order = '03', runAlways = true)\n\t    void testChangeSetRunAlways() {\n\t        println 'invoke runAlways'\n\t    }\n\t\n\t    @ChangeSet(author = 'testuser', id = 'test4', order = '04')\n\t    @ChangeEnv('development')\n\t    void testChangeSetEnvDevelopment() {\n\t        println 'invoke test for env development'\n\t    }\n\t\n\t    @ChangeSet(author = 'testuser', id = 'test5', order = '05')\n\t    @ChangeEnv('test')\n\t    void testChangeSetEnvTest() {\n\t        println 'invoke test for env test'\n\t    }\n\t}\n
\n

RUN MIGRATION

\n

Version 0.9 and up: The manual line adding below is no longer needed. Mongogee migration service will be executed automatically if changeEnabled is set to true (which is also default).

\n

Version 0.8 and below: Add following to init/BootStrap.groovy

\n
class BootStrap {\n\n    MongogeeService mongogeeService\n\n    def init = { servletContext ->\n        // ...\n\n        mongogeeService.execute()\n\n    }\n\n    // ...\n}\n
\n

CHANGE LOG

\n

v 0.9.1

\n\n

v 0.9

\n\n

v 0.8

\n\n

v 0.7 and under

\n\n

CONTRIBUTORS

\n

Bin Le (bin.le.code@gmail.com)

\n

LICENSE

\n

Apache License Version 2.0. (http://www.apache.org/licenses/)

\n" }, { "deprecated": "Since Grails 3.2 - Use GORMs built-in support for multitenancy.", "bintrayPackage": { "name": "multitenant", "repo": "plugins", "owner": "troutbird", "desc": null, "labels": [ "multitenant" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/ejaz-ahmed/grails-multitenant-plugin/issues", "latestVersion": "0.1", "updated": "2016-03-31T13:31:54.724Z", "systemIds": [ "org.grails.plugins:multitenant" ], "vcsUrl": "https://github.com/ejaz-ahmed/grails-multitenant-plugin" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

# TOC

\n

grails-multitenant-plugin

\n

This plugin is sponsored by IP Geolocation. It adds multitenant support for grails 3 applications based on hibernate filters. Tenants are resolved using spring security.

\n

Note

\n

Only branch grails3.0.xhibernate4 is working. Rest of branches are for GORM5 which has broken the way hibernate filters are applied. So they won't work. Also, this plugin works only for Grails 3.0 and 3.1. For later versions of grails, use GORM's built in multi-tenancy support.\nThe work on this plugin has been stopped in favor of Grails internal support for Multi-tenant architecture.

\n

Installation

\n

Add following dependency in build.gradle

\n
compile 'org.grails.plugins:multitenant:0.1'\n
\n

Add configClass attribute in application.yml under dataSource section like this:

\n
 configClass: org.grails.plugin.multitenant.HibernateMultitenantConfiguration \n
\n

Architecture

\n

This plugin uses single database single schema differentiator based technique to identify tenants.

\n

Resolving Tenant

\n

Currently it resolves tenant using spring security. So you have to edit spring security user domain class to implement TenantIdentifier trait like this:

\n
class User implements Serializable, TenantIdentifier\n
\n

It add userTenantId property to User domain class and injects two closures dynamically to this domain

\n

withTenantId

\n

This closure executes a particular code inside its scope with a tenantId supplied as parameters even if the logged in user does not belong to that tenant. You can only execute idempotent code inside this block. If your code is query, or some other read only operation, it will execute that with supplied tenantId. If your code is going to change something in database, it will use tenantId of logged in user. Be careful . .

\n
User.withTenantId(12){\n\n// Your code goes here\n\n}\n\n
\n

withoutTenantId

\n

As the name states, you can bypass tenantId filter temporarily to do operations not specific to any tenant.

\n
User.withoutTenantId(){\n\n// You code goes here\n\n
\n

The code in this scope should be read only as is the case with withTenantId method above.

\n

Multitenat Domain Classes

\n

You have to implement Multitenant trait in all domain classes you want to be multitenant.

\n
class Book implement Multitenant\n
\n

This will add a property tenantId to domain class and three methods as below:

\n
Long tenantId\n\n    def beforeInsert() {\n        if(tenantId == null){\n            tenantId = tenantResolverService.resolveTenant()\n        }\n    }\n\n    def beforeValidate() {\n        if(tenantId == null){\n            tenantId = tenantResolverService.resolveTenant()\n        }\n    }\n\n    def beforeUpdate() {\n        if(tenantId == null){\n            tenantId = tenantResolverService.resolveTenant()\n        }\n    }\n    \n
\n

So if you want to use these methods in any of multitenant domain class, you have to reproduce above code along with your own implementation as yours will overwrite these methods.

\n

TenantResolverService

\n

This plugin provide TenantResolverService to your application which can be injected anywhere just like normal grails services. It provides only one method resolveTenant which provides tenantId of current user. Multitenant plugin makes extensive use of this service at various places inside the code. Multitenant filter intercepts controller actions only. If you want to do some multitenant stuff inside a service then you should call that service from controller or use withTenantId as below:

\n
def tenantResolverService\nUser.withTenantId(tenantResolverService.resolveTenant()){\n // your code here\n}\n
\n

About ipgeolocation.io

\n

IP Geolocation's IP intelligence APIs help developer's find out Geolocation, Tim Zone, Local Currency and much more from just an IP address. For more information checkout document page

\n" }, { "bintrayPackage": { "name": "neo4j", "repo": "plugins", "owner": "grails", "desc": "GORM for Neo4j", "labels": [ "gorm", "graph", "neo4j" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails/gorm-neo4j/issues", "latestVersion": "8.1.0", "updated": "2024-03-15T21:01:53.000Z", "systemIds": [ "org.grails.plugins:neo4j" ], "vcsUrl": "https://github.com/grails/gorm-neo4j" }, "documentationUrl": "https://gorm.grails.org/latest/neo4j/manual/", "mavenMetadataUrl": "https://repo1.maven.org/maven2/org/grails/plugins/neo4j/maven-metadata.xml", "readme": "

GORM for Neo4j

\n

This project implements GORM for the Neo4j 3.x Graph Database using the Bolt Java Driver.

\n

For more information see the following links:

\n\n

For the current development version see the following links:

\n\n" }, { "bintrayPackage": { "name": "newrelic", "repo": "plugins", "owner": "agorapulse", "desc": "Grails NewRelic plugin", "labels": [ "newrelic" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/agorapulse/grails-newrelic/issues", "latestVersion": "5.2.0", "updated": "2019-07-16T09:16:45.158Z", "systemIds": [ "org.grails.plugins:newrelic" ], "vcsUrl": "https://github.com/agorapulse/grails-newrelic" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

NewRelic Grails Plugin

\n

\"Build\n\"Download\"

\n

Introduction

\n

This plugin will make New Relic instrumentation available to a Grails project.
\nIt is a port to Grails 3.X of the original NewRelic Grails Plugin, originally written by CP Lim.\nStarting with version 5.2.0 the plugin is compatibile with Grails 4.

\n

Grails NewRelic Plugin provides the following Grails artefacts:

\n\n

New Relic needs to be installed on the running application server in order for the plugin to work.\nThis is extensively documented by the New Relic team.\nOnce installed, New Relic Browser will need to be configured for manual instrumentation .

\n

Installation

\n

Declare the plugin dependency in the build.gradle file, as shown here:

\n
repositories {\n    ...\n    maven { url "http://dl.bintray.com/agorapulse/plugins" }\n}\ndependencies {\n    ...\n    compile "org.grails.plugins:newrelic:5.2.0"\n}\n
\n

Thanks to binary incompability of trait between the different Groovy version, current version can be used with Grails 3.2.11 and newer.\nTry older versions of this plugin if you need to use it with older version of Grails.

\n

Config

\n

By default the New Relic RUM code will only be enabled for Production environments.\nIf you need it to be enabled for other environments, make sure that it is explicitly enabled in your configs

\n
newrelic:\n    enabled: true\n
\n

Usage

\n

Once New Relic and this plugin has been added to your web application, you are ready to add the tags to your page(s).
\nNew Relic provides some best practices on when to all these tag methods.
\nIdeally, you would only need to add it to your layout page(s) as follows:

\n
<!DOCTYPE html>\n<html>\n<head>\n    <meta name="viewport" content="width=device-width, initial-scale=1">\n    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>\n    <newrelic:browserTimingHeader/>\n    <!-- other tags -->\n</head>\n<body>\n    <!-- more tags -->\n    <newrelic:browserTimingFooter/>\n</body>\n</html>\n
\n

However, if there are more GSP that need these tags, then just make sure they are added at the appropriate locations in the DOM.

\n

Enabling NewRelic for Development

\n

NewRelic should be enabled in the production environment as per the instructions here, but if you need to enable this in other environments, make sure that the configs have enabled NewRelic for your environment, and add the following to your GRAILS_OPT environment

\n
export GRAILS_OPTS="-javaagent:/path/to/newrelic.jar"\n
\n

The next time you execute 'run-app' or 'run-war', NewRelic instrumentation code will be included in your generated HTML pages.

\n

On newer versions of grails that use a forked jvm, you may need to include the java agent in your tomcat configuration. This is in BuildConfig.groovy.

\n
grails.tomcat.jvmArgs = ["-javaagent:/path/to/newrelic.jar"]\n
\n

BONUS - Installing and configuring NewRelic on AWS Elastic Beanstalk

\n

Here are some instructions to install/configure NewRelic app AND server monitoring on AWS ElasticBeanstalk.\nIt will also call the NewRelic deployment API each time you start a new env.

\n

1- Create a folder src/main/webapp/.ebextensions, a folder src/main/webapp/.ebextensions/files and add the newrelic.jar in it.

\n

2- Create a file src/main/webapp/.ebextensions/files/newrelic.yml.sh (to dynamically generate newrelic.yml based on app env properties)

\n
cat << EOF\ncommon: &default_settings\nlicense_key: '$NR_LICENSE'\nenable_auto_transaction_naming: false\napp_name: $NR_APPNAME\nEOF\n
\n

3- Create a file src/main/webapp/.ebextensions/newrelic.sh

\n
#!/bin/sh\n# New Relic (Application monitoring)\nmkdir /var/lib/newrelic\nmv ./.ebextensions/files/newrelic*.jar /var/lib/newrelic/\nbash ./.ebextensions/files/newrelic.yml.sh > /var/lib/newrelic/newrelic.yml\n\n# New Relic Agent (Server monitoring)\nrpm -Uvh https://yum.newrelic.com/pub/newrelic/el5/x86_64/newrelic-repo-5-3.noarch.rpm\nyum -y install newrelic-sysmond\n/usr/sbin/nrsysmond-config \ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdset license_key=$NR_LICENSE\n/etc/init.d/newrelic-sysmond start\n\n# New Relic deployment event\nexport AP_VERSION=`` `cat ./META-INF/grails.build.info | grep info.app.version | cut -d= -f2` ``\njava -jar /var/lib/newrelic/newrelic.jar deployment \ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdrevision=$AP_VERSION\n
\n

4- Create a file src/main/webapp/.ebextensions/app.config

\n
container_commands:\n  newrelic:\n    command: "bash -x .ebextensions/newrelic.sh"\n
\n

Then, in your Beanstalk app config options, add -javaagent:/var/lib/newrelic/newrelic.jar to the JVM command line parameter and set NR_LICENSE and NR_APPNAME env properties.

\n

Bugs

\n

To report any bug, please use the project Issues section on GitHub.

\n" }, { "bintrayPackage": { "name": "novamail", "repo": "plugins", "owner": "novadge", "desc": "The Novamail plug-in provides e-mail sending and retrieving capabilities to a Grails application. It is also capable of sending emails asynchronously by using a scheduled Job", "labels": [ "mail" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/Novadge/novamail/issues", "latestVersion": "0.1.8", "updated": "2020-05-25T03:31:08.817Z", "systemIds": [ "org.grails.plugins:novamail", "com.novadge.plugins:novamail", "novamail:novamail" ], "vcsUrl": "https://github.com/Novadge/novamail" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Novamail

\n

\"Build

\n

Description

\n

The Novamail plug-in provides e-mail sending and receiving capabilities to a Grails application. It is also capable of sending emails asynchronously by using a scheduled Job.

\n

Configuration

\nI recommend you add the following to application.groovy config file. Please create the file if it doesn't exist. \n

Add your email provider properties to grails configuration file: Example\nAssuming you want to add config for a gmail account for 'john@gmail.com' then add the following to your grails config file.

\n

novamail.hostProps = [

\n
  ["host":'imap.gmail.com'],\n  ["mail.imap.host":"imap.gmail.com"],\n  ["mail.store.protocol": "imaps"],\n  ["mail.imap.socketFactory.class": "javax.net.ssl.SSLSocketFactory"],\n  ["mail.imap.socketFactory.fallback": "false"],\n  ["mail.imaps.partialfetch":"false"],\n  ["mail.mime.address.strict": "false"],\n  ["mail.smtp.starttls.enable": "true"],\n  ["mail.smtp.host": "smtp.gmail.com"],\n  ["mail.smtp.auth": "true"],\n  ["mail.smtp.socketFactory.port": "465"],\n  ["mail.smtp.socketFactory.class": "javax.net.ssl.SSLSocketFactory"],\n  ["mail.smtp.socketFactory.fallback": "false"]\n
\n

]\n

\n \n novamail{\n
       hostname= System.getenv("CS_HOSTNAME")\n       username= System.getenv("CS_USERNAME")\n       password= System.getenv("CS_PASSWORD")\n       store= System.getenv("CS_STORE")\n       \n       }\n
\n
\n

Avoid having passwords in your code. Store them as Environment variables.

\n

Side note

\nNovamail will try to use predefined host props for some popular email providers if you do not provide hostProps\n

Usage

\n

Inject messagingService into your class

\n

def messagingService

\n

messagingService is a Grails service that provides a single method called sendEmail that takes parameters.\nPlease note that 'sendEmail()' is overloaded 'see http://en.wikipedia.org/wiki/Function_overloading' and can take various variations of parameters.

\n
\nOne simple form is:\n\nsendEmail(Map map)\n\n

Where ......

\n

map contains parameters...\nmap.to: Email recipient eg recipient@gmail.com

\n

map.subject: "Your email subject"

\n

map.body: "The body of your message"

\n

Example

\n

An example usage can be seen below.

\n\n
Class YourController{\n \n    def messagingService\n    ...\n    def yourMethod(){\n        def map = [to:"recipient@gmail.com",subject:"Email subject",body:"email body"]\n        messagingService.sendEmail(map)\n    \n    }\n\n}\n
\n
\n

Second form

\n

Requirements

\n

To use the messagingService with mapped parameters, you need to declare a\nmap with the required variables. These are,\n\nhostname, username, password,\nfrom, to, subject, body, html, attachments, hostProps

\n

.

\n\n

html is boolean that defaults to true,

\n

attachments is a List of type File (for file attachments) and is optional,\nand

\n

hostProps is a map of host properties (see above).

\n

If hostname, username, password, from, hostProps have been set in the\nConfig.groovy file, they do not have to be added to your map parameter.\nhtml defaults to true so that can be\nomitted as well except when set explicitly (your choice).

\n

Example Usage

\n\n
Class MyController {\n    def messagingService\n    \n    def myMethod() {\n        ...\n        def map = [username:"john@doe.com", password:"john_password", from:"JOHN Doe<john@doe.com>", to: "recepeitn@gmail.com", subject: "Hello there!", body: "Just to test out awesome Novamail"]\n        messagingService.sendEmail(map) // Call the messagingService sendEmail method passing in the map\n    }\n}\n
\n
\n" }, { "deprecated": "Duplicate entry of plugin from same author. This entry should probably be removed from the registry.", "bintrayPackage": { "name": "org.grails.plugins:csv", "repo": "plugins", "owner": "vsachinv", "desc": "Grails CSV plugin", "labels": [ "csv" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/vsachinv/grails-csv/issues", "latestVersion": null, "updated": "2017-11-15T13:54:48.264Z", "systemIds": [ ], "vcsUrl": "https://github.com/vsachinv/grails-csv" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

grails-csv

\n

The csv plugin provides utility methods and also support for reading/writing to csv files. It uses opencsv library.

\n

Installation

\n

Add dependency to your build.gradle for Grails 3.x:

\n
repositories {\n  ...\n  maven { url "http://dl.bintray.com/sachinverma/plugins" }\n}\n\ndependencies {\n    compile 'org.grails.plugins:grails-csv:1.0.1'\n}\n
\n

For further info: [https://github.com/vsachinv/grails-csv/wiki/Grails-CSV]

\n" }, { "deprecated": "Source repository is merged into https://github.com/grails-plugins/grails-database-migration and closed. This entry should probably be removed from the registry to avoid confusion.", "bintrayPackage": { "name": "org.grails.plugins:database-migration", "repo": "plugins", "owner": "yamkazu", "desc": "Grails database-migration plugin", "labels": [ "migration" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/yamkazu/database-migration/issues", "latestVersion": "2.0.0.RC1", "updated": "2016-04-14T09:18:54.806Z", "systemIds": [ "org.grails.plugins:database-migration" ], "vcsUrl": "https://github.com/yamkazu/database-migration" }, "documentationUrl": "https://yamkazu.github.io/database-migration/", "mavenMetadataUrl": null, "readme": "

This repository has been merged into the https://github.com/grails-plugins/grails-database-migration

\n" }, { "bintrayPackage": { "name": "enforcer", "repo": "plugins", "owner": "virtualdogbert", "desc": "A plugin for enforcing business rules/permissions, that works with Spring Security Core, is easier to implement, and extend. It can also be used as an alternative to Spring Security ACL", "labels": [ "acl", "business-rules", "permissions", "Security", "spring-security" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/virtualdogbert/Enforcer/issues", "latestVersion": "3.0.0", "updated": "2023-07-16T17:59:10.000Z", "systemIds": [ "io.github.virtualdogbert:enforcer" ], "vcsUrl": "https://github.com/virtualdogbert/Enforcer" }, "documentationUrl": "https://virtualdogbert.github.io/Enforcer/", "mavenMetadataUrl": "https://repo1.maven.org/maven2/io/github/virtualdogbert/enforcer/maven-metadata.xml", "readme": "

The Enforcer Plugin, is a lightweight, easier to maintain/extend/use, alternative to Spring Security ACL. The plugin works off of an EnforcerService and an Enforce Ast transform, The service takes up to 3 closures, a predicate, a failure(defaults to an EnforcerException if not specified) and a success(defaulted to a closure that returns true).

\n

For documentation see the github page:\ndocumentation

\n" }, { "displayName": "feature-switch", "bintrayPackage": { "name": "org.grails.plugins:feature-switch", "repo": "grails-plugins", "owner": "desirable-objects", "desc": "Grails feature-switch plugin", "labels": [ ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/antony/grails-feature-switch/issues", "latestVersion": "1.0", "updated": "2016-03-31T13:31:54.885Z", "systemIds": [ "org.grails.plugins:feature-switch" ], "vcsUrl": "https://github.com/antony/grails-feature-switch" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": null }, { "deprecated": "Duplicate of geb plugin at https://github.com/grails/geb. This entry should probably be removed from the registry.", "bintrayPackage": { "name": "org.grails.plugins:geb", "repo": "plugins", "owner": "grails", "desc": "Grails geb plugin", "labels": [ "testing", "geb" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails3-plugins/geb/issues", "latestVersion": "1.0.1", "updated": "2016-04-01T15:40:48.261Z", "systemIds": [ "org.grails.plugin:geb" ], "vcsUrl": "https://github.com/grails3-plugins/geb/" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Grails 3.x Geb Plugin

\n

\"Build

\n

Geb Functional Testing for Grails 3.0

\n

This plugin just provides the Geb dependencies and a create-functional-test command for generating Geb tests in a Grails 3.0 app. For further reference please see the Geb documentation

\n

##\ufffd\ufffd Examples

\n

If you are looking for examples check:

\n

Geb/Grails example project

\n

or Grails 3.x functional test suite where Geb tests are used extensively.

\n

Additional Drivers

\n

To setup additional drivers you need to add the driver to your build.gradle for example:

\n
testRuntime 'com.github.detro:phantomjsdriver:1.2.0'\n
\n

Then you need to create a GebConfig.groovy file to your src/test/resources/ directory. For example:

\n
/*\n\tThis is the Geb configuration file.\n\n\tSee: http://www.gebish.org/manual/current/#configuration\n*/\nimport org.openqa.selenium.chrome.ChromeDriver\nimport org.openqa.selenium.firefox.FirefoxDriver\nimport org.openqa.selenium.phantomjs.PhantomJSDriver\n\nwaiting {\ntimeout = 2\n}\ndriver = { new PhantomJSDriver() }\n
\n" }, { "bintrayPackage": { "name": "gorm-envers", "repo": "plugins", "owner": "yingliang-du", "desc": "The gorm-envers Grails plugin add auditting functionality to GROM in your Grails application using Hibernate Envers. The only thing you need to do is add @Audited annotation to the Domain Class that you want to audit. Hibernate Envers will create audit table in the Database for the annotated domain and log all change history.", "labels": [ "envers" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/Yingliang-Du/gorm-envers-grails-plugin/issues", "latestVersion": "0.3", "updated": "2016-03-31T13:31:54.924Z", "systemIds": [ "org.grails.plugins:gorm-envers" ], "vcsUrl": "https://github.com/Yingliang-Du/gorm-envers-grails-plugin" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

gorm-envers-grails-plugin

\n

A Grails Plugin for Auditing GORM Domain class using Hibernate Envers. This plugin only work with Grails 3 or later.

\n

Using the gorm-envers plugin in your Grails application

\n

Add the release version of the plugin dependency in build.gradle

\n
compile ("org.grails.plugins:gorm-envers:0.3") {\n\texclude module: 'hibernate-core'\n\texclude module: 'hibernate-entitymanager'\n}\n
\n

Build from source

\n

Install gorm-envers plugin on your machine

\n
git clone https://github.com/Yingliang-Du/gorm-envers-grails-plugin.git\ncd gorm-envers-grails-plugin/gorm-envers\ngrails clean\ngrails compile\ngrails install\n
\n

Add the installed plugin dependency in build.gradle

\n
compile ("org.grails.plugins:gorm-envers:0.4-SNAPSHOT") {\n\texclude module: 'hibernate-core'\n\texclude module: 'hibernate-entitymanager'\n}\n
\n

Audit domain classes in your Grails application

\n

Add @Audited annotation to the domain class you want to audit

\n

That is it!

\n

Auditing methods added to domain classes

\n\n

Demo after install gorm-envers plugin

\n
cd pathto/gorm-envers-grails-plugin/demo\ngrails \ngrails> clean\ngrails> compile\ngrails> run-app\n
\n\n" }, { "bintrayPackage": { "name": "aws", "repo": "grails-plugins", "owner": "grails-aws", "desc": "Grails AWS Plugin", "labels": [ "aws" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails-aws/grails-aws/issues", "latestVersion": "2.0.4", "updated": "2017-11-07T07:28:55.078Z", "systemIds": [ "org.grails.plugins:grails-aws" ], "vcsUrl": "https://github.com/grails-aws/grails-aws" }, "documentationUrl": "https://grails-aws.github.io/grails-aws/", "mavenMetadataUrl": null, "readme": "

Amazon Web Services Grails Plugin

\n

\"Build\n\"Coverage

\n

A Grails plugin for interacting with Amazon Web Services

\n

Currently supports S3 and S3S

\n

Getting Started

\n

Add the plugin to the plugins section of grails-app/conf/BuildConfig.groovy

\n
dependencies {\n    runtime 'org.grails.plugins:grails-aws:2.0.1'\n}\n
\n

Configure the plugin in grails-app/conf/application.yaml

\n
grails:\n    plugin:\n        aws:\n            credentials:\n                accessKey: ASDASDASDASD\n                secretKey: fASDd1h/1Hf/0pkQ+nJx+oRSm36t/R8jUI/A1D2\n            s3:\n                bucket: my-bucket\n
\n

Documentation

\n\n

Contributing

\n\n

Changelog

\n

2.0.1 - October 13 2015

\n\n

1.9.13.4 - September 11 2015

\n\n

1.9.13.0 - January 5 2015

\n\n

1.7.5.0 - April 11 2014

\n\n

1.6.7.4 - January 15 2014

\n\n

1.6.7.1 - December 10 2013

\n\n

1.2.12.4 - November 30 2013

\n\n

1.2.12.3 - September 30 2012

\n\n

1.1.9.2 - May 10 2011

\n\n

TODO

\n\n" }, { "comment": "There are releases for v0.2.1 and v0.2.2 but no artifacts are published.", "bintrayPackage": { "name": "flyway", "repo": "plugins", "owner": "saw303", "desc": "Grails flyway plugin", "labels": [ "migration", "flyway" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/saw303/grails-flyway/issues", "latestVersion": "0.2", "updated": "2016-05-09T15:25:38.033Z", "systemIds": [ "org.grails.plugins:grails-flyway" ], "vcsUrl": "https://github.com/saw303/grails-flyway.git" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Flyway - Database Migration for Grails

\n

This plugin provides Flyway support for your Grails 3 application.

\n" }, { "deprecated": "Source repository is gone.", "bintrayPackage": { "name": "org.grails.plugins:grails-markdown", "repo": "grails-plugins", "owner": "tednaleid", "desc": "Grails grails-markdown plugin", "labels": [ "markdown" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://bitbucket.org/tednaleid/grails-markdown/issues", "latestVersion": "3.0.0", "updated": "2016-03-31T13:31:56.039Z", "systemIds": [ "org.grails.plugins:grails-markdown" ], "vcsUrl": "https://bitbucket.org/tednaleid/grails-markdown" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": null }, { "bintrayPackage": { "name": "cas-client", "repo": "maven", "owner": "cwang", "desc": null, "labels": [ ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/cwang/grails3-cas-client/issues", "latestVersion": "3.0", "updated": "2016-03-31T13:31:54.822Z", "systemIds": [ "org.grails.plugins:grails3-cas-client" ], "vcsUrl": "https://github.com/cwang/grails3-cas-client.git" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

grails3-cas-client

\n" }, { "bintrayPackage": { "name": "grooscript", "repo": "grooscript", "owner": "cdrchops", "desc": "Grooscript Grails Plugin", "labels": [ "grooscript", "groovy", "javascript" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/cdrchops/grooscript-plugins/issues", "latestVersion": "1.3.0", "updated": "2017-05-19T17:34:31.179Z", "systemIds": [ "org.grails.plugins:grooscript" ], "vcsUrl": "https://github.com/cdrchops/grooscript-plugins" }, "documentationUrl": "https://www.grooscript.org/doc.html#_grails_plugin", "mavenMetadataUrl": null, "readme": "

Grooscript plugins

\n

\"Build\n\"Build

\n

This is a gradle multiproject where the grooscript gradle and grails plugins sources are.

\n

More info about grooscript

\n

Multi-project

\n

Grails 3 build, there are 5 projects:

\n\n

(*) published in bintray

\n

TO-DO

\n\n

Build

\n

To make all checks (included geb tests using chrome remote driver if you built test apps):

\n
./gradlew check\n
\n

Test jar & components

\n

To test jar generation with components, first test app must be created with:

\n
./gradlew createTestApp\n
\n

Later, run the test with:

\n
./gradlew checkComponentInJar\n
\n" }, { "bintrayPackage": { "name": "iCalendar", "repo": "plugins", "owner": "saw303", "desc": "Grails iCalendar plugin", "labels": [ "calendar", "icalendar" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/saw303/grails-ic-alender/issues", "latestVersion": "0.6.4", "updated": "2019-06-06T07:11:40.354Z", "systemIds": [ "org.grails.plugins:iCalendar" ], "vcsUrl": "https://github.com/saw303/grails-ic-alender.git" }, "documentationUrl": "https://saw303.github.io/grails-ic-alender/", "mavenMetadataUrl": null, "readme": null }, { "deprecated": "The source repository url for this entry is redirecting to the source repository of another plugin with the same name by ZenHarbinger. This entry in the registry should probably be removed to avoid confusion.", "bintrayPackage": { "name": "org.grails.plugins:jasypt-encryption", "repo": "grails-plugins", "owner": "dtanner", "desc": "Integration with Jasypt, allows easy encryption of information including Hibernate/GORM integration", "labels": [ "encryption", "jasypt" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/dtanner/grails-jasypt/issues", "latestVersion": "2.0.2", "updated": "2017-01-20T05:46:31.670Z", "systemIds": [ "org.grails.plugins:jasypt-encryption" ], "vcsUrl": "https://github.com/dtanner/grails-jasypt" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

The Grails Jasypt Encryption plugin provides strong field-level encryption support on Grails GORM String fields. It leverages the Jasypt simplified encryption framework that makes working with the Java Cryptographic Extension (JCE) much easier.

\n

It also comes with the Bouncy Castle encryption provider, which gives you access to the very secure AES algorithm.

\n

Installation

\n
plugins {\n    compile "org.grails.plugins:jasypt-encryption:x.x.x"\n}\n
\n

If your app is using Grails 4 or higher, then use version 4.0.3 of this plugin.
\nIf your app is using Grails 3 or higher, then use version 2.0.2 of this plugin.
\nIf your app is using Grails 2 and Hibernate 4, then use version 1.3.1 of this plugin.
\nIf your app is using Grails 2 and Hibernate 3, then use version 1.2.1 of this plugin.

\n

Configuration

\n

You'll then need to configure the encryption in your Grails configuration using a stanza like this (make sure to change the password):

\n
jasypt {\n    algorithm = "PBEWITHSHA256AND256BITAES-CBC-BC"\n    providerName = "BC"\n    password = "<your very secret passphrase>"\n    keyObtentionIterations = 1000\n}\n
\n

This will configure your encryption to use a 256 bit AES algorithm to do the encryption. Key generation will also be repeated 1000 times (to slow down any brute force attacks). Changing any of these values will result in different results (and will also prevent the ability to decrypt previously encrypted information).

\n

External Config Files in Grails

\n

You can put the encryption configuration in Config.groovy, but a better location would be an external configuration file that does not get checked into source code (and can vary based on environment). Just put something like this in your Config.groovy file to define an external config file:

\n
def configFIlePath = System.getenv('ENCRYPTION_CONFIG_LOCATION') ?: "file:${userHome}/.jasypt"\ngrails.config.locations = [configFilePath]\n
\n

This enables you to set an environment variable with the location of the encryption configuration, otherwise it will look for a .encryption file in the current user's home (useful for developers).

\n

Enabling "Unlimited" Encryption in Java

\n

Because of American export standards, and the notion that cryptographically strong algorithms are "munitions", you'll want to make sure that the encryption policy jars that came with your installation of Java allow "unlimited" encryption, rather than the default "strong" (which are actually pretty weak).

\n

To check to see what level of encryption your installation of Java has, you'll need to do one of two things:\nA: Run the code from this gist on github

\n

or

\n

B: crack open your $JAVA_HOME/jre/lib/security/local_policy.jar to see what's inside.:

\n
% cd /tmp\n% cp $JAVA_HOME/jre/lib/security/local_policy.jar .\n% jar xvf local_policy.jar\n inflated: META-INF/MANIFEST.MF\n inflated: META-INF/JCE_RSA.SF\n inflated: META-INF/JCE_RSA.RSA\n  created: META-INF/\n inflated: default_local.policy\n\n% cat default_local.policy\n// Country-specific policy file for countries with no limits on crypto strength.\ngrant {\n    // There is no restriction to any algorithms.\n    permission javax.crypto.CryptoAllPermission;\n};\n
\n

If the permissions look like that, you're set. Mac laptops bought in the US have this configured by default, all other installations I've seen have needed to be upgraded (including all Linux distros).

\n

Installing the new jar files is easy, just go download the "Java Cryptography Extension (JCE)" under "Other Downloads" on Oracle's website.

\n

Unzip the zip file and copy the jar files into your $JAVA_HOME/jre/lib/security directory to overwrite the existing, limited encryption jars.

\n
#make a backup copy of your existing files\nmkdir old_java_security\ncp -r $JAVA_HOME/jre/lib/security old_java_security\n\nunzip jce_policy-6.zip\nsudo cp jce/*.jar $JAVA_HOME/jre/lib/security\n
\n

Defining Fields in your Domain to Encrypt

\n

Defining fields in your domain object that you want to be encrypted within the database is easy once the plugin is installed and configured, just define the "type" within the domain class' mapping:

\n
package com.bloomhealthco.domain\n\nimport com.bloomhealthco.jasypt.GormEncryptedStringType\n\nclass Member {\n    String firstName\n    String lastName\n    String ssn\n    static mapping = {\n    \tssn type: GormEncryptedStringType\n    }\n}\n
\n

One other caveat, if you're setting the length of the field within the database schema, you'll need to give yourself extra room as the encrypted value will be longer than the unencrypted value was. This length will depend on the encryption algorithm that you use. It's easy to write an integration test that can spit out all of the encrypted lengths for you. See testEncryptionWithLongNamesFit() in the https://github.com/ZenHarbinger/grails-jasypt/blob/master/src/test/projects/sample/src/integration-test/groovy/com/bloomhealthco/domain/JasyptDomainEncryptionTests.groovy for an example.

\n

Custom Encryption Types

\n

As of version 1.1 the plugin provides 'Gorm' versions of all the built in Encrypted types provide by the jasypt plugin, http://www.jasypt.org/hibernate.html.

\n

It is also possible to define your own GORM encrypted types. This happens in two steps. First, you need a UserType that handles the encryption. This might be a class you have already from a existing java application or you could extend the jasypt class AbstractEncryptedAsStringType. Second, you define a new Gorm Encrypted type that composes that UserType to provide the wiring to the Grails configuration.

\n

Here's an example that can encrypt joda-time dates (requires the joda-time jar to work):

\n
package com.bloomhealthco.jasypt\n\nimport org.jasypt.hibernate.type.AbstractEncryptedAsStringType\nimport org.joda.time.LocalDate;\n\npublic class EncryptedLocalDateAsStringType extends AbstractEncryptedAsStringType {\n\n    protected Object convertToObject(String string) {\n        if (!string) return null\n        if (!(string =~ /\\d{4}-\\d{2}-\\d{2}/)) throw new IllegalArgumentException("String does not match YYYY-MM-dd pattern")\n        new LocalDate(string)\n    }\n\n    protected String convertToString(Object object) {\n        if (!object) return null\n        if (object.class != LocalDate) throw new IllegalArgumentException("Expected ${LocalDate.name} but was ${object.class.name}")\n        object.toString("YYYY-MM-dd")\n    }\n\n    public Class returnedClass() { LocalDate }\n}\n\npublic class GormEncryptedLocalDateAsStringType extends JasyptConfiguredUserType<EncryptedLocalDateAsStringType> {\n}\n\n
\n

Further Documentation

\n

For now, documentation is a little light. There's a test project checked in as part of the repository that shows the plugin being used (and has tests that exercise the functionality). The Patient domain object has encrypted firstName and lastName fields on it.

\n

Release Notes

\n\n" }, { "deprecated": "Source repository for this entry is archived. This entry should probably be removed from the registry.", "bintrayPackage": { "name": "org.grails.plugins:json-annotations-marshaller", "repo": "plugins", "owner": "anthofo", "desc": "Grails json-annotations-marshaller plugin", "labels": [ "json" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/anthofo/grails3-json-annotations-marshaller/issues", "latestVersion": "1.0", "updated": "2015-07-03T11:50:00.000Z", "systemIds": [ "org.grails.plugins:json-annotations-marshaller" ], "vcsUrl": "https://github.com/anthofo/grails3-json-annotations-marshaller" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

json-apis

\n

Grails plugin for managing multiple JSON apis using domain class annotations

\n

The goal of this plugin is to help convert Grails domain classes into various\nJSON representations needed in different parts of your web application or to\nsupport various API versions.

\n

Features:

\n\n

Example of use

\n

Several API variants can be easily defined in domain classes by annotating properties with\nJsonApi and providing a list of API profile names under which that property should appear in the\nresulting JSON. Marking a property with the JsonApi annotation but providing no API names will\ninclude that property in all APIs. The database identity property will always be included\nautomatically. One could for instance define the following domain class:

\n
import grails.plugins.jsonapis.JsonApi\n\nclass User {\n\t@JsonApi\n\tString screenName\n\n\t@JsonApi('userSettings')\n\tString email\n\n\t@JsonApi(['userSettings', 'detailedInformation'])\n\tString twitterUsername\n}\n
\n

Then in the controller one would call the desired named JsonApi configuration to get only\nthe fields defined for that API. The following code:

\n
JSON.use("detailedInformation")\nrender person as JSON\n
\n

...would convert the person object into JSON containing the id, screenName and twitterUsername\nproperties but not the email. It works for collections as well, converting each collection\nmember using the same API profile that was used to convert the parent:

\n
static hasMany = [\n\tpets: Pet\n]\n@JsonApi('detailedInformation')\nSet pets\n
\n

To include a domain object's parent in a JSON API, declare a belongsTo property explicitly\nand annotate it with JsonApi (but be careful not to create circular paths by including both\nends of a belongsTo/hasMany pair):

\n
static belongsTo = [\n\tuser:User\n]\n\n@JsonApi('petDetails') \nUser user\n
\n

JSONBuilder is supported, too:

\n
JSON.use("userSettings")\nrender(contentType: "text/json") {\n    user = User.first()\n    pet = Pet.first()\n}\n
\n

Future plans

\n\n" }, { "bintrayPackage": { "name": "log-hibernate-stats", "repo": "plugins", "owner": "ishults", "desc": "A simple plugin to log Hibernate statistics across controller actions.", "labels": [ "logging" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/ishults/log-hibernate-stats/issues", "latestVersion": "1.0.20", "updated": "2016-03-31T13:31:55.695Z", "systemIds": [ "org.grails.plugins:log-hibernate-stats" ], "vcsUrl": "https://github.com/ishults/log-hibernate-stats" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

logHibernateStats

\n

Summary

\n

A simple Grails 3 plugin to log Hibernate statistics on controller actions.

\n

For the Grails 2 plugin code and documentation, see: https://github.com/ishults/log-hibernate-stats/tree/grails_2.x

\n

Configuration and Usage

\n

To add this plugin, in your build.gradle add:

\n
repositories {\n  ...\n  maven { url "http://dl.bintray.com/ishults/plugins" }\n}\ndependencies {\n  ...\n  compile "org.grails.plugins:log-hibernate-stats:1.0.20"\n}\n
\n

Then just update your config (such as application.yml) to add

\n
logHibernateStats:\n    enabled: 'ALWAYS'// From ALWAYS, ALLOWED, NEVER\n
\n

for the environments you want to track statistics for.

\n

Then in your logback.groovy set:

\n
logger 'grails.app.controllers.org.grails.plugins.LogHibernateStatsInterceptor',\n    DEBUG, ['STDOUT'], false // Or INFO\n
\n

You should now be seeing output like:

\n
INFO  controller.ControllerFilters  -\n############## Hibernate Stats ##############\nAction:                     /controller/actionName\n\nTransaction Count:          2\nFlush Count:                1\nPrepared Statement Count:   2\n\nTotal time:                 500 ms\n#############################################\n
\n

after each request. If you set the logging to 'debug', you will also see:

\n
DEBUG  controller.ControllerFilters  -\n### Start logging for action: controller/actionName ###\n
\n

at the start of each action (useful if logSql is enabled too).

\n

If instead you'd like to target only specific actions, you can set

\n
logHibernateStats.enabled = 'ALLOWED'\n
\n

and instead append the parameter '_logHibernateStats=true' to your request. This will isolate the logging to just that request.

\n

It is recommended to keep the plugin enabled value at 'NEVER' by default, and setting it to 'ALLOWED' or 'ALWAYS' when debugging in development.

\n

Caveats

\n\n

Credits

\n

Plugin created by Igor Shults.

\n

Official Grails 3.x plugin page here: https://bintray.com/ishults/plugins/org.grails.plugins%3Alog-hibernate-stats/view

\n

Official Grails 2.x plugin page here: http://grails.org/plugin/log-hibernate-stats

\n

If you're not interested in running this as a plugin, I wrote a blog post on some standalone code here: http://www.objectpartners.com/2014/04/22/tracking-hibernate-statistics-across-grails-actions/

\n

Inspired by a post on Hibernate logging by Himanshu Seth: http://www.intelligrape.com/blog/2011/11/07/grails-find-number-of-queries-executed-for-a-particular-request/

\n" }, { "bintrayPackage": { "name": "quartz-monitor", "repo": "plugins", "owner": "jamescookie", "desc": "Grails quartz-monitor plugin", "labels": [ "quartz", "scheduling" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/jamescookie/quartz-monitor/issues", "latestVersion": "1.3", "updated": "2016-04-19T21:51:32.924Z", "systemIds": [ "org.grails.plugins:quartz-monitor" ], "vcsUrl": "https://github.com/jamescookie/quartz-monitor" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

#Quartz Monitor Plugin for Grails

\n

Allows you to view and administer all your Quartz jobs in one place.

\n

##Prerequisites

\n

This plugin requires the Quartz and Asset Pipeline plugins to run.

\n

##Usage

\n

Once you have the Quartz plugin installed and have created some jobs, then you will probably start wondering if they are all running as desired.

\n

This is where you need the 'Quartz Monitor' plugin.

\n

Simply install the plugin and go to the URL: http://localhost:8080//quartz and you will find all a list of all the jobs you have scheduled to run.

\n

##Enhanced Experience

\n

To have the page keep you constantly up to date requires jQuery. It will still work without jQuery, but it won't look as good.

\n

##Configuration

\n

There are various configuration options, all start with quartz.monitor:

\n

###layout

\n

Allows you to change the sitemesh layout that page will use. Defaults to 'main'.

\n

###showTriggerNames

\n

If this is set to true, then the names of the triggers will be shown in the list - useful if you have multiple triggers for the same job.

\n

###showCountdown

\n

Will add javascript to the page in order to show a countdown to when the job will fire next, unless this is set to 'false'.

\n

###showTickingClock

\n

Will add javascript to the page in order to show a clock with the current time, unless this is set to 'false'.

\n" }, { "bintrayPackage": { "name": "p6spy-ui", "repo": "plugins", "owner": "grails", "desc": "Grails p6spy-ui plugin", "labels": [ "logging", "p6spy" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/burtbeckwith/grails-p6spy-ui/issues", "latestVersion": "3.0.0", "updated": "2016-04-01T15:40:04.213Z", "systemIds": [ "org.grails.plugins:p6spy-ui" ], "vcsUrl": "https://github.com/burtbeckwith/grails-p6spy-ui" }, "documentationUrl": "https://burtbeckwith.github.io/grails-p6spy-ui/", "mavenMetadataUrl": null, "readme": null }, { "bintrayPackage": { "name": "paypal-payments", "repo": "plugins", "owner": "novadge", "desc": "Accept and process payments with Paypal SDK", "labels": [ "payment", "paypal" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/Novadge/paypal-payments/issues", "latestVersion": "0.1.0", "updated": "2016-03-31T13:31:54.940Z", "systemIds": [ "org.grails.plugins:paypal-payments" ], "vcsUrl": "https://github.com/Novadge/paypal-payments" }, "documentationUrl": "https://Novadge.github.io/paypal-payments/", "mavenMetadataUrl": null, "readme": "

paypal payments

\n

Accept and process payments with Paypal REST API

\n

Introduction

\n

The Paypal payments plugin simplifies the integration of Paypal into Grails applications. With this plugin, you are not required to be a Paypal sdk guru in order to accept payments.

\n

This guide documents how to use the plugin to process payments for Grails applications.

\n

Getting Started

\n

I will assume that you already have your Grails application designed and ready to accept payments. A demo application will be sufficient for this exercise.

\n

####Create a Paypal account\nYou will need to create a Paypal account and obtain API keys for a Paypal app. The Paypal app will represent your Grails application. To create a Paypal app, please visit [https://developer.paypal.com/developer/applications/](Paypal developer page) to create a sandbox account.

\n

The Sandbox account will allow you to play around with most of the API features available. It is also a good way to test your application integration before moving over to a live environment.

\n

####Obtain your client id and client secret\nObtain the API keys for your sandbox account/app and add it to your Grails config file [Config.groovy for grails 2.x and application.groovy for grails 3.x]. Here's what my config file looks like:

\n
paypal.email="omasiri@novadge.com"\npaypal.clientId = 'your client id'\npaypal.sandbox.clientId = 'your client id'\npaypal.clientSecret = 'your client secret'\npaypal.sandbox.clientSecret ='your client secret'\npaypal.endpoint = "https://api.paypal.com"\npaypal.sandbox.endpoint = "https://api.sandbox.paypal.com"\n
\n

Notice that I added config for sandbox and live environment. The reason is to be able to switch between both environments during app development.

\n

####Create a grails controller and add required actions\nCreate a grails controller. Personally, I called my own controller PaypalController.

\n
grails create-controller com.mypackage.Paypal\n
\n

####Add required actions

\n

Normally, Paypal payments requires three steps to complete.

\n
    \n
  1. Make approval request to paypal.
  2. \n
  3. Approval - Customer approves the payment
  4. \n
  5. Execution - Process response from Paypal in order to capture the payment.
  6. \n
\n

Approval Step

\n

For the approval step, here's my action inside my PaypalController.\nInject paypalService into your controller like this...

\n
def paypalService\n
\n

And then create your Controller action

\n
import com.paypal.base.Constants\n...\n\ndef approve() {\n\n    String clientId = grailsApplication.config.paypal.clientId\n    String clientSecret = grailsApplication.config.paypal.clientSecret\n    String endpoint = grailsApplication.config.paypal.endpoint\n    Map sdkConfig = [(Constants.CLIENT_ID): clientId,\n                     (Constants.CLIENT_SECRET): clientSecret,\n                     (Constants.ENDPOINT): endpoint]\n    def accessToken = paypalService.getAccessToken(clientId, clientSecret, sdkConfig)\n    def apiContext = paypalService.getAPIContext(accessToken, sdkConfig)\n\n\n    BigDecimal total = formatNumber(number: params.amount, minFractionDigits: 2) as BigDecimal\n\n    def details = paypalService.createDetails(subtotal: "12.50")\n    def amount = paypalService.createAmount(currency: currencyCode, total: "12.50", details: details)\n\n    def transaction = paypalService.createTransaction(amount: amount, description: "your description", details: details)\n    def transactions = [transaction]\n\n    def payer = paypalService.createPayer(paymentMethod: 'paypal')\n    def cancelUrl = "http://myexampleurl/cancel"\n    def returnUrl = "http://mypaypalController/execute"\n\n    def redirectUrls = paypalService.createRedirectUrls(cancelUrl: cancelUrl, returnUrl: returnUrl)\n\n    def payment\n    try {\n        // create the paypal payment\n        payment = paypalService.createPayment(\n            payer: payer, intent: 'sale',\n            transactionList: transactions,\n            redirectUrls: redirectUrls,\n            apiContext: apiContext)\n    }\n    catch (e) {\n        flash.message = "Could not complete the transaction because: ${e.message ?: ''}"\n        redirect controller: 'bill', action: "show", id: params.refId\n        return\n    }\n\n    def approvalUrl = ""\n    def retUrl = ""\n    // retrieve links from returned paypal object\n    for (Links links in payment?.links) {\n        if (links?.rel == 'approval_url') {\n            approvalUrl = links.href\n        }\n        if (links?.rel == 'return_url') {\n            retUrl = links.href\n        }\n    }\n\n    redirect url: approvalUrl ?: '/', method: 'POST'\n}\n
\n

Approval

\n

The customer will be redirected to the Paypal website for approval. After the customer approves or\ncancels the payment, Paypal will either call the returnUrl or cancelUrl you provided depending on\nwhat action the customer performs.

\n
def execute() {\n\n    String clientId = grailsApplication.config.paypal.clientId\n    String clientSecret = grailsApplication.config.paypal.clientSecret\n    String endpoint = grailsApplication.config.paypal.endpoint\n    Map sdkConfig = [:] //= grailsApplication.config.paypal.sdkConfig//[mode: 'live']\n    //sdkConfig['grant-type'] = "client_credentials"\n    sdkConfig[Constants.CLIENT_ID] = clientId\n    sdkConfig[Constants.CLIENT_SECRET] = clientSecret\n    sdkConfig[Constants.ENDPOINT] = endpoint\n    def accessToken = paypalService.getAccessToken(clientId, clientSecret, sdkConfig)\n    def apiContext = paypalService.getAPIContext(accessToken, sdkConfig)\n    //the paypal website will add params to the call to your app. Eg. PayerId, PaymentId\n    // you will use the params to 'execute' the payment\n    def paypalPayment = paypalService.createPaymentExecution(paymentId: params.paymentId, payerId: params.PayerID, apiContext)\n\n    def map = new JsonSlurper().parseText(paypalPayment.toString())\n\n    redirect url: "to your url"\n}\n
\n

Authors and Contributors

\n

Omasirichukwu Joseph Udeinya (@omasiri)

\n

Support or Contact

\n

Please feel free to reach out to us for assistance with this plugin and we\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdll help you sort it out.

\n" }, { "bintrayPackage": { "name": "paystack-grails", "repo": "plugins", "owner": "dubems", "desc": "Plugin to communicate with paystack API", "labels": [ "payment" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/dubems/paystack-grails/issues", "latestVersion": "1.0.5", "updated": "2020-07-30T18:43:08.745Z", "systemIds": [ "org.grails.plugins:paystack-grails" ], "vcsUrl": "https://github.com/dubems/paystack-grails" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": null }, { "bintrayPackage": { "name": "postgresql-extensions", "repo": "plugins", "owner": "kaleidos", "desc": "This plugin provides hibernate user types to support for Postgresql Native Types like Array, HStore, JSON as well as new criterias to query this native types.", "labels": [ "postgresql", "gorm" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/kaleidos/grails-postgresql-extensions/issues", "latestVersion": "7.0.0", "updated": "2019-07-29T19:41:48.286Z", "systemIds": [ "org.grails.plugins:postgresql-extensions" ], "vcsUrl": "https://github.com/kaleidos/grails-postgresql-extensions" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Grails Postgresql Extensions

\n

THIS BRANCH (master) IS FOR GRAILS 4 AND HIBERNATE 5.4

\n

\"Download\"\n\"Download\"\n\"Download\"\n\"Download\"\n\"Build

\n

This is a grails plugin that provides hibernate user types to use Postgresql native types such as Array, Hstore, Json,\nJsonb... from a Grails application. It also provides new criterias to query this new native types.

\n

Currently the plugin supports array, hstore, json and jsonb fields as well as some query methods.\nMore native types and query methods will be added in the future.

\n\n

Installation

\n

The Grails 3 version supports both Hibernate 4.X (versions 4.x.x of the plugin) and Hibernate 5.X (versions 5.x.x of the\nplugin). In build.gradle add the jcenter repository and the following dependency to install the plugin:

\n
repositories {\n    ...\n    jcenter()\n    ...\n}\n\ndependencies {\n    ...\n    compile 'org.grails.plugins:postgresql-extensions:<version>'\n    ...\n}\n
\n

Postgresql driver

\n

You also need to install the Postgresql jdbc driver. You can see all available Postgresql jdbc libraries versions at\nMVN Repository.

\n
dependencies {\n    ...\n    provided 'org.postgresql:postgresql:9.4.1211.jre7'\n    ...\n}\n
\n

Hibernate plugin

\n

It's also necessary to install the Grails-Hibernate plugin. Depending if you use Hibernate 4 or Hibernate 5 you'll need\ndifferent dependencies. Please make sure you use the latest versions of the plugin and the hibernate dependencies

\n
// Hibernate 4\nbuildscript {\n    ...\n    dependencies {\n        ...\n        classpath "org.grails.plugins:hibernate4:6.0.3"\n    }\n}\n\ndependencies {\n    ...\n    compile "org.grails.plugins:hibernate4"\n    compile "org.hibernate:hibernate-core:4.3.11.Final"\n    compile "org.hibernate:hibernate-ehcache:4.3.11.Final"\n    ...\n}\n
\n
// Hibernate 5\nbuildscript {\n    ...\n    dependencies {\n        ...\n        classpath "org.grails.plugins:hibernate5:6.0.3"\n    }\n}\n\ndependencies {\n    ...\n    compile "org.grails.plugins:hibernate5"\n    compile "org.hibernate:hibernate-core:5.1.1.Final"\n    compile "org.hibernate:hibernate-ehcache:5.1.1.Final"\n    ...\n}\n
\n

Configuration

\n

After install the plugin you have to use a new Postgresql Hibernate Dialect in your application. Add it to the\ngrails-app/conf/application.yml file:

\n
---\ndataSource:\n    pooled: true\n    jmxExport: true\n    driverClassName: org.postgresql.Driver\n    username: user\n    password: password\n    url: jdbc:postgresql://localhost:5432/db_name\n    dbCreate: update\n\nhibernate:\n    dialect: net.kaleidos.hibernate.PostgresqlExtensionsDialect\n
\n

If you just only add the dialect, hibernate will create a new sequence for every table to generate the sequential ids\nused for the primary keys instead of a global sequence for all your tables.

\n

If you're using Hibernate 4 you can also deactivate this behaviour and create only one unique sequence for all the tables with the following\nproperty in your datasource definition:

\n
dataSource:\n  postgresql:\n    extensions:\n      sequence_per_table: false\n}\n
\n

For Hibernate 5 add the following to grails-app/conf/application.groovy:

\n
grails.gorm.default.mapping = {\n    id generator: 'org.hibernate.id.enhanced.SequenceStyleGenerator', params: [prefer_sequence_per_entity: true]\n}\n
\n

Please be aware that Hibernate 5 has changed the default name of the sequences so for a domain class TestMapJson the\ntable name is test_map_json and the sequence name is seq_test_map_json in Hibernate 4 and testmapjson_seq in\nHibernate 5.

\n

Native Types

\n

Arrays

\n

The plugin supports the definition of Integer, Long, Float, Double, String, and Enum arrays in your domain\nclasses.

\n

The Enum arrays behaves almost identical to Integer arrays in that they store and retrieve an array of ints. The\ndifference, however, is that this is used with an Array of Enums, rather than Ints. The Enums are serialized to their\nordinal value before persisted to the database. On retrieval, they are then converted back into their original Enum\ntype.

\n

Example

\n
import net.kaleidos.hibernate.usertype.ArrayType\n\nclass Like {\n    Integer[] favoriteNumbers = []\n    Long[] favoriteLongNumbers = []\n    Float[] favoriteFloatNumbers = []\n    Double[] favoriteDoubleNumbers = []\n    String[] favoriteMovies = []\n    Juice[] favoriteJuices = []\n    UUID[] favoriteMovieUUIDs = []\n\n    static enum Juice {\n        ORANGE(0),\n        APPLE(1),\n        GRAPE(2)\n\n        private final int value\n        Juice(int value)  { this.value = value }\n    }\n\n    static mapping = {\n        favoriteNumbers type:ArrayType, params: [type: Integer]\n        favoriteLongNumbers type:ArrayType, params: [type: Long]\n        favoriteFloatNumbers type:ArrayType, params: [type: Float]\n        favoriteDoubleNumbers type:ArrayType, params: [type: Double]\n        favoriteMovies type:ArrayType, params: [type: String]\n        favoriteJuices type:ArrayType, params: [type: Juice]\n        favoriteMovieUUIDs type:ArrayType, params: [type: UUID]\n    }\n}\n
\n

Now you can create domain objects using lists (or arrays) of integers, longs and strings and when you save the object\nit will be stored as an postgresql array:

\n
def myLikes = new Like(favoriteNumbers: [5, 17, 9, 6],\n                     favoriteLongNumbers: [123, 239, 3498239, 2344235],\n                     favoriteFloatNumbers: [0.3f, 0.1f],\n                     favoriteDoubleNumbers: [100.33d, 44.11d],\n                     favoriteMovies: ["Spiderman", "Blade Runner", "Starwars"],\n                     favoriteJuices: [Like.Juice.ORANGE, Like.Juice.GRAPE])\nmyLikes.save()\n
\n

And now, with psql:

\n
=# select * from like;\n\n id |  favorite_long_numbers    |  favorite_float_numbers   |  favorite_double_numbers  |        favorite_movies                 | favorite_numbers | favorite_juices\n----+---------------------------+---------------------------+---------------------------+----------------------------------------+------------------+----------------\n  1 | {123,239,3498239,2344235} | {0.3,0.1}                 | {100.33,44.11}            | {Spiderman,"Blade Runner",Starwars}    | {5,17,9,6}       | {0,2}\n
\n

Criterias

\n

The plugin also includes some hibernate criterias to use in your queries. Please check the\nservices\nand the tests\ncreated to see all usage examples.

\n

You can also check the official Postgresql Array operators.

\n
Contains
\n

With this criteria you can get all the rows that contain all the values in the array field. To use it just use the new\ncriteria pgArrayContains:

\n
// number can be just a value...\ndef number = 3\ndef result = Like.withCriteria {\n    pgArrayContains 'favoriteNumbers', number\n}\n\n// ...or a list\ndef numbers = [5, 17]\ndef result = Like.withCriteria {\n    pgArrayContains 'favoriteNumbers', numbers\n}\n\n// If using enums, pass the enum right through\ndef juices = Like.Juice.ORANGE\ndef result = Like.withCriteria {\n    pgArrayContains 'favoriteJuices', juices\n}\n\n
\n

Is contained

\n

With this criteria you can get all the rows that are contained by the values. To use it just use the new criteria\npgArrayIsContainedBy:

\n
// movie can be just a string or a list\ndef movie = "Starwars" // or movie = ["Starwars"]\ndef result = Like.withCriteria {\n    pgArrayIsContainedBy 'favoriteMovies', movie\n}\n\n// The plugin also support joins\ndef movies = ["Starwars", "Matrix"]\ndef results = User.withCriteria {\n    like {\n        pgArrayIsContainedBy 'favoriteMovies', movies\n    }\n}\n
\n

Overlaps

\n

With this criteria you can get all the rows that contains any of the values. To use it just use the new criteria\npgArrayOverlaps:

\n
def result = Like.withCriteria {\n    pgArrayOverlaps 'favoriteNumbers', numbers\n}\n
\n

Is Empty

\n

With this criteria you can get all the rows that contains an-empty array in the selected field. To use it just use the\nnew criteria pgArrayIsEmpty:

\n
def result = Like.withCriteria {\n    pgArrayIsEmpty 'favoriteMovies'\n}\n
\n

Is Not Empty

\n

With this criteria you can get all the rows that contains a not empty array in the selected field. To use it just use\nthe new criteria pgArrayIsNotEmpty:

\n
def result = Like.withCriteria {\n    pgArrayIsNotEmpty 'favoriteMovies'\n}\n
\n

Is Empty or Contains

\n

This criteria is a mix of the pgContains and pgIsEmpty. Sometimes you have to execute 'pgContains' criteria if the\nlist has elements or a 'pgIsEmpty' if the list is empty. It could be something like this:

\n
def numbers = ... // A list with zero or more elements\ndef result = Like.withCriteria {\n    if (numbers) {\n        pgArrayContains 'favoriteNumbers', numbers\n    } else {\n        pgArrayIsEmpty 'favoriteMovies'\n    }\n}\n
\n

With pgIsEmptyOrContains you can write the previous code as follows:

\n
def numbers = ... // A list with zero or more elements\ndef result = Like.withCriteria {\n    pgArrayIsEmptyOrContains 'favoriteNumbers', numbers\n}\n
\n

Equals

\n

With this criteria you can get all the rows that are equal to a value. To use it just use the new criteria pgArrayEquals:

\n
def result = Like.withCriteria {\n    pgArrayEquals 'favoriteNumbers', numbers\n}\n
\n

Not Equals

\n

With this criteria you can get all the rows that are not equal to a value. To use it just use the new criteria\npgArrayNotEquals:

\n
def result = Like.withCriteria {\n    pgArrayNotEquals 'favoriteNumbers', numbers\n}\n
\n

ILike

\n

With this criteria you can get all the rows that are ilike to a value. To use it just use the new criteria pgArrayILike.

\n

It only can be used on arrays of string.

\n

It uses the ilike syntaxis, so you can do for example:

\n
def result = Like.withCriteria {\n    pgArrayILike 'favoriteMovies', "%tarwar%"\n}\n
\n

Hstore

\n

The first thing you need to do is install hstore support in Postgresql. In Debian/Ubuntu you have to install the\npostgresql-contrib package:

\n
sudo apt-get install postgresql-contrib-9.4\n
\n

Once the package is installed in the system you have to create the extension in the database you want to use hstore into:

\n
CREATE EXTENSION hstore;\n
\n

You can test that the hstore extension is correctly installed running:

\n
=# SELECT 'foo=>bar, xxx=>yyy'::hstore;\n           hstore\n----------------------------\n "foo"=>"bar", "xxx"=>"yyy"\n(1 row)\n
\n

Using Hstore

\n

You only have to define the domain class with a Map attribute and use the Hibernate user type HstoreMapType.

\n
import net.kaleidos.hibernate.usertype.HstoreMapType\n\nclass TestHstore {\n\n    Map testAttributes\n    String anotherProperty\n\n    static mapping = {\n        testAttributes type: HstoreMapType\n    }\n}\n
\n

Now you can create and instance of the domain class. Due to a limitation of the Hstore Postgresql type you can only\nstore Strings as key and value.

\n
def instance = new TestHstore(testAttributes: [foo: "bar"], anotherProperty: "Groovy Rocks!")\ninstance.save()\n\ndef instance2 = new TestHstore(testAttributes: [xxx: 1, zzz: 123], anotherProperty: "")\ninstance2.save()\n
\n
=# select * from test_hstore;\n id | version | another_property | test_attributes\n----+---------+------------------+-----------------\n  1 |       0 | Groovy Rocks!    | "foo"=>"bar"\n  2 |       0 |                  | "xxx"=>"1", "zzz"=>"123"\n
\n

Hstore Criterias

\n

The following criteria operations are available to query rows using the Hstore custom type. You can\ncheck the services\nand the tests\ncreated to see all usage examples.

\n

You can also check the official Postgresql Hstore operators.

\n
Contains Key
\n

With this operation you can search for rows that contain an Hstore with the key passed as parameter.

\n
def wantedKey = "my-custom-key"\ndef result = MyDomain.withCriteria {\n    pgHstoreContainsKey "attributes", wantedKey\n}\n
\n
Contains
\n

You can search for data that contains certain pairs of key and value.

\n
def result = Users.withCriteria {\n    pgHstoreContains 'configuration', ["language": "es"]\n}\n
\n
Is Contained
\n

The operation is contained can be used when looking for rows that has all the elements in the map\npassed as parameter.

\n
def result = TestHstore.withCriteria {\n    pgHstoreIsContained 'testAttributes', ["1": "a", "2": "b"]\n}\n
\n

The example above returns the rows that contains elements like:

\n
testAttributes = ["1": "a"]\ntestAttributes = ["2": "b"]\ntestAttributes = ["1": "a", "2": "b"]\n
\n

This criteria can also be used to look for exact matches.

\n
ILike Value
\n

With this operation you can search for rows that contain an Hstore in which any value matches (ilike) to the parameter.\nIt uses the ilike syntaxis, so you can do for example:

\n
def wantedValue = "%my-value%"\ndef result = MyDomain.withCriteria {\n    pgHstoreILikeValue "attributes", wantedKey\n}\n
\n

JSON

\n

To define a json field you only have to define a Map field and use the JsonMapType hibernate user type.

\n
import net.kaleidos.hibernate.usertype.JsonMapType\n\nclass TestMapJson {\n    Map data\n\n    static constraints = {\n    }\n    static mapping = {\n        data type: JsonMapType\n    }\n}\n
\n

Using Json

\n

Now you can create and instance of the domain class:

\n
def instance = new TestMapJson(data: [name: "Iv\ufffd\ufffd\ufffd\ufffdn", age: 35, hasChilds: true, childs: [[name: 'Judith', age: 8], [name: 'Adriana', age: 5]]])\ninstance.save()\n
\n
=# select * from test_map_json;\n\n id | version | data\n----+---------+-------------------------------------------------------------------------------------------------------------\n  1 |       0 | {"hasChilds":true,"age":35,"name":"Iv\ufffd\ufffd\ufffd\ufffdn","childs":[{"name":"Judith","age":8},{"name":"Adriana","age":5}]}\n
\n

As you can see the plugin converts to Json automatically the attributes and the lists in the map type.

\n

Json Criterias

\n

The plugin provides some criterias to query json fields. You can check the official\nPostgresql Json functions and operators in case you\nneed additional ones.

\n
Has field value
\n

With this criteria you can check if a json field contains some value in some key. To use it just use the criteria\npgJsonHasFieldValue:

\n
def obj1 = new TestMapJson(data: [name: 'Iv\ufffd\ufffd\ufffd\ufffdn', lastName: 'L\ufffd\ufffd\ufffd\ufffdpez']).save(flush: true)\ndef obj2 = new TestMapJson(data: [name: 'Alonso', lastName: 'Torres']).save(flush: true)\ndef obj3 = new TestMapJson(data: [name: 'Iv\ufffd\ufffd\ufffd\ufffdn', lastName: 'P\ufffd\ufffd\ufffd\ufffdrez']).save(flush: true)\n\ndef result = TestMapJson.withCriteria {\n    pgJsonHasFieldValue 'data', 'name', 'Iv\ufffd\ufffd\ufffd\ufffdn'\n}\n
\n

The previous criteria will return all the rows that have a name attribute in the json field data with the value\nIv\ufffd\ufffd\ufffd\ufffdn. In this example obj1 and obj3.

\n
Generic criterion
\n

With this criterion you can use more operators using a syntax close to the one described in Postgresql documentation.\nTo use it just use pgJson:

\n
def obj1 = new TestMapJson(data: [name: 'Iv\ufffd\ufffd\ufffd\ufffdn', lastName: 'L\ufffd\ufffd\ufffd\ufffdpez', other: [followersCount: 150]]).save(flush: true)\ndef obj2 = new TestMapJson(data: [name: 'Alonso', lastName: 'Torres', other: [followersCount: 148]]).save(flush: true)\ndef obj3 = new TestMapJson(data: [name: 'Iv\ufffd\ufffd\ufffd\ufffdn', lastName: 'P\ufffd\ufffd\ufffd\ufffdrez', other: [followersCount: 149]]).save(flush: true)\n\ndef result1 = TestMapJson.withCriteria {\n    pgJson 'data', '->>', 'name', 'ilike', '%iv%'\n}\n
\n

The previous query will return all the rows that have a name attribute in the json field data containing iv\n(case insensitive). In this example obj1 and obj3.

\n
def result2 = TestMapJson.withCriteria {\n    pgJson 'data', '#>>', '{other, followersCount}', '>', 149\n}\n
\n

The previous query will return all the rows that have an other value whose followersCount value is greater than\n149. In this example obj1.

\n

Jsonb

\n

Since postgresql-extensions version 4.4.0 it is possible to use Postgresql Jsonb\ninstead of just json. You need to use at least Postgresql 9.4.

\n

To define a jsonb field you only have to define a Map field and use the JsonbMapType hibernate user type.

\n
import net.kaleidos.hibernate.usertype.JsonbMapType\n\nclass TestMapJsonb {\n    Map data\n\n    static constraints = {\n    }\n    static mapping = {\n        data type: JsonbMapType\n    }\n}\n
\n

Jsonb Criterias

\n

The same criterias implemented for Json are valid for Jsonb. Besides that, there are some criterias that are only\nvalid for Jsonb. Check the documentation.

\n
Contains
\n

With this criteria you can get all the rows that contain all the values in the map. To use it just use the criteria\npgJsonContains:

\n
def obj1 = new TestMapJsonb(data: [a: 'foo', b: '1']).save(flush: true)\ndef obj2 = new TestMapJsonb(data: [b: 1, d: '2']).save(flush: true)\ndef obj3 = new TestMapJsonb(data: [a: 'foo', b: '1', c: 'test',]).save(flush: true)\n\ndef result = TestMapJsonb.withCriteria {\n    pgJsonbContains data, [a: 'foo', b: '1']\n}\n
\n

The previous criteria will return all the rows that contains all the keys/values ([a: 'foo', b: '1'] in the example)\nin the data field. In this example will return obj1 and obj3.

\n

Is contained

\n

With this criteria you can get all the rows that are contained by the values. To use it just use the criteria\npgArrayIsContainedBy:

\n
def obj1 = new TestMapJsonb(data: [a: 'foo', b: '1']).save(flush: true)\ndef obj2 = new TestMapJsonb(data: [b: 1, d: '2']).save(flush: true)\ndef obj3 = new TestMapJsonb(data: [b: '1', a: 'foo', c: 'test',]).save(flush: true)\n\ndef result = TestMapJsonb.withCriteria {\n    pgJsonbIsContained data, [a: 'foo', b: '1', c: 'test']\n}\n
\n

The previous criteria will return all the rows that are contained in the map. In the example it will retun the objects\nobj1 and obj3.

\n

Order

\n

Random order

\n

Sometimes you need to get some results ordered randomly from the database. Postgres provides a native function to do\nthat. So you can write something like this:

\n
select * from foo order by random();\n
\n

The plugin now offers a new order method to do this random sorting:

\n
import static net.kaleidos.hibernate.order.OrderByRandom.byRandom\n\nclass MyService {\n    List<TestMapJsonb> orderByRandom() {\n        return TestMapJsonb.withCriteria {\n            order byRandom()\n        }\n    }\n}\n
\n

Sql formula

\n

You may need to do a more complex sorting. Imagine that you have a table with a jsonb column and you want to order\nby a field in that json. Using sql you can write:

\n
select * from foo order by (data->'name') desc\n
\n

With the plugin you can do the same with a new order method called sqlFormula:

\n
import static net.kaleidos.hibernate.order.OrderBySqlFormula.sqlFormula\n\nclass MyService {\n    List<TestMapJsonb> orderByJson() {\n        return TestMapJsonb.withCriteria {\n            order sqlFormula("(data->'name') desc")\n        }\n    }\n}\n
\n

It's important to note that the "raw" sql is appended to the criteria, so you need to be sure that it's valid because\nif not you'll get a sql error during runtime.

\n

Authors

\n

You can send any questions to:

\n\n

Collaborations are appreciated :-)

\n

Release Notes

\n

Version | Date | Comments\n------- | ------------| ---------\n7.0.0 | 29/Jul/2019 | Grails 4 (Hibernate 5.4): Add support for Grails 4 and Hibernate 5.4. Thanks to James Hardwick and Zhuravskiy Vitaliy.\n6.1.0 | 24/Sep/2018 | Grails 3 (Hibernate 5.2): Fix #30. Thanks to John Keith and jglapa.\n5.3.0 | 24/Sep/2018 | Grails 3 (Hibernate 5): Fix #30. Thanks to John Keith and jglapa.\n4.8.0 | 24/Sep/2018 | Grails 3 (Hibernate 4): Fix #30. Thanks to John Keith and jglapa.\n6.0.0 | 05/Jun/2018 | Grails 3: Add support for Hibernate 5.2. #114. Thanks to Alexey Zhokhov and Feng Yu.\n5.2.0 | 03/Nov/2017 | Grails 3 (Hibernate 5): Merged #107 and #109.\n5.1.0 | 22/May/2017 | Grails 3 (Hibernate 5): Change db credentials to make it compatible with Postgresql 9.6.\n4.7.0 | 22/May/2017 | Grails 3 (Hibernate 4): Change db credentials to make it compatible with Postgresql 9.6.\n5.0.1 | 21/May/2017 | Grails 3 (Hibernate 5): Fix #96. Thanks to jglapa.\n4.6.9 | 21/May/2017 | Grails 3 (Hibernate 4): Fix #96. Thanks to jglapa.\n5.0.0 | 07/Nov/2016 | Grails 3: Add support for Hibernate 5.1. Upgrade dialect to Postgresql 9.4, Grails to 3.2.2 and GORM to 6.0.3.\n4.6.8 | 03/Nov/2016 | Grails 3: Add support for generic Json/Jsonb criteria #95. Thanks to Sabst.\n4.6.7 | 01/Nov/2016 | Grails 3: Add UUID arrays. Thanks to Tom Potts. Fix #87\n5.0.0-RC1 | 28/Oct/2016 | Grails 3: Add support for Hibernate 5. Thanks to Alexey Zhokhov and Eric Helgeson.\n4.6.6 | 24/Apr/2016 | Grails 3: Migrate (almost) all Java code to Groovy + @CompileStatic. No new features added.\n4.6.5 | 31/Dec/2015 | Grails 3: Fix #84. Starting Grails 3.0.10 the default sequence_per_table parameter was not working.\n4.6.4 | 29/Dec/2015 | Grails 3: Cleanup and new jar file with the same functionality as previous version. It seems that version 4.6.3 is corrupted.\n4.6.3 | 08/Dec/2015 | Grails 3: Add new criterias for Jsonb: contains and isContained.\n4.6.2 | 05/Dec/2015 | Grails 3: Cleanup old code for support Hstore in old Grails versions.\n4.6.1 | 02/0ct/2015 | Plugin migrated to Grails 3.\n4.6.1 | 21/Sep/2015 | Hibernate 4.x. Fix #76.\n4.6.0 | 08/Sep/2015 | Hibernate 4.x. Add support to order by a sql formula and by random. Fix #72.\n4.5.0 | 02/Jun/2015 | Hibernate 4.x. GR8Conf Hackergarten! Merge PRs: #62, #66, #67, #68, #69.\n3.4.0 | 02/Jun/2015 | Hibernate 3.x. GR8Conf Hackergarten! Add Jsonb support for Hibernate 3.x #64.\n4.4.0 | 15/Mar/2015 | Hibernate 4.x. Add support for Jsonb.\n3.3.0 | 18/Aug/2014 | Hibernate 3.x. Fix #49. Configure sequence per table or a global sequence for all tables.\n4.3.0 | 17/Aug/2014 | Hibernate 4.x. Fix #49. Configure sequence per table or a global sequence for all tables.\n3.2.0 | 02/Aug/2014 | Hibernate 3.x. pgJsonHasFieldValue criteria.\n4.2.0 | 28/Jul/2014 | Hibernate 4.x. pgJsonHasFieldValue criteria.\n3.1.0 | 25/Jul/2014 | Add JSON support for Hibernate 3.x. It's now possible to store and read domain classes with map types persisted to json.\n4.1.0 | 24/Jul/2014 | Add JSON support. It's now possible to store and read domain classes with map types persisted to json.\n4.0.0 | 18/Jul/2014 | Version compatible with Hibernate 4.x.\n3.0.0 | 18/Jul/2014 | Version compatible with Hibernate 3.x.\n0.9 | 16/Jun/2014 | Add new array criterias: pgArrayEquals, pgArrayNotEquals.\n0.8.1 | 24/Apr/2014 | Fix NPE when array is null.\n0.8 | 24/Apr/2014 | Added support for Double and Float arrays. Refactored the ArrayType to be used as a parametrized type.\n0.7 | Unreleased | New HstoreMapType and update plugin to Grails 2.2.5.\n0.6.8 | 22/Apr/2014 | Fix NPE in HstoreType.\n0.6.7 | 14/Feb/2014 | Support Java Arrays in criterias.\n0.6.6 | 14/Feb/2014 | New criteria pgArrayIsEmptyOrContains.\n0.6.5 | 13/Feb/2014 | Fix bug deleting instances with Hstore type. Thanks to Manuel Unno Vio!\n0.6.4 | 30/Jan/2014 | Convert automatically the keys of Hstore to string.\n0.6.3 | 19/Jan/2014 | Display the class name during startup when detecting a hstore property.\n0.6.2 | Unreleased | Refactor some tests.\n0.6.1 | 28/Nov/2013 | Update postgresql jdbc driver to version 9.2 and do not export hibernate plugin.\n0.6 | 21/Nov/2013 | Use a more complete Hstore parser. Thanks to Moritz Kobel!\n0.5.1 | 10/Nov/2013 | Change base directory to compile AST before the plugin classes. Thanks to Moritz Kobel!\n0.5 | 08/Nov/2013 | Add criteria operation for Hstore types.\n0.4.1 | Unreleased | Compile AST before the project itself.\n0.4 | 28/Oct/2013 | Add support to Hstore. It's only possible to save and get, but no queries has been implemented.\n0.3 | 18/Sep/2013 | Add support to define the schema name for the sequences.\n0.2 | 25/Aug/2013 | Support for arrays of Enums with automatic serialization/deserialization to ordinal integer value. Thanks to Matt Feury!\n0.1.1 | 22/Jul/2013 | Some refactors of the code. No functionality added.\n0.1 | 16/Jul/2013 | Initial version of the plugin with support for integer, long and string array types and criterias pgArrayContains, pgArrayIsContainedBy, pgArrayOverlaps, pgArrayIsEmpty and pgArrayIsNotEmpty.

\n" }, { "bintrayPackage": { "name": "qrcode", "repo": "plugins", "owner": "technipelago", "desc": "A plugin that allows you to create QR codes as part of your Grails application without the need for an external service", "labels": [ "qrcode" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/goeh/grails-qrcode/issues", "latestVersion": "0.9", "updated": "2016-03-31T13:31:55.574Z", "systemIds": [ "org.grails.plugins:qrcode" ], "vcsUrl": "https://github.com/goeh/grails-qrcode" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

This plugin allows you to create QR codes as part of your Grails\napplication without the need for an external service.

\n

Installation

\n

For Grails 2 use version 0.7, for Grails 3 use version 0.8+.

\n

Grails 2

\n

Add a dependency in BuildConfig.groovy:

\n
grails.project.dependency.resolution = {\n  // ...\n  plugins {\n    compile ':qrcode:0.7'\n    // ...\n  }\n}\n
\n

Grails 3

\n

Add a dependency in build.gradle

\n
compile 'org.grails.plugins:qrcode:0.9'\n
\n

Usage

\n

QrcodeController

\n

Render text QRCode at default size (300x300px)

\n
.../qrcode/text/Hello+World\n
\n

Render text QRCode in 30x30px

\n
.../qrcode/text?w=30&text=test\n
\n

\"QRCode\"

\n
Render url QRCode\n\n.../qrcode/url?u=http://grails.org/plugin/qrcode\n
\n

Configuration

\n

The maximum value of the width parameter can be configured with qrcode.size.max (default 1024).

\n
qrcode.size.max = 2048\n
\n

QrCodeService

\n
qrCodeService.renderPng("test", 30, outputStream)\n
\n

Tag Library

\n

Namespace: qrcode

\n

Render text as QRCode

\n
<qrcode:image height="100" width="100" text="TEST TEXT"/>\n
\n

If you want to include a QRCode image in an email and you use a GSP to render email content you must set attribute absolute="true".\nOtherwise the image url will not start with http:// and will probably not render correct.

\n
<qrcode:image height="100" width="100" text="#648357" alt="Invoice #648357" absolute="true"/>\n
\n

Render current request url as QRCode

\n
<qrcode:url width="64"/>\n
\n

Render vCard contact information as QRCode

\n

In this example we have a method on the Person domain class that returns contact information as a vCard formatted String.

\n
class Person {\n    ...\n    transient String getVcard() {\n        def s = new StringBuilder()\n        s << "BEGIN:VCARD\\n"\n        s << "VERSION:3.0\\n"\n        s << "N:${lastName};${firstName};;;\\n"\n        s << "FN: ${fullName}\\n"\n        s << "ORG:${companyName}\\n"\n        s << "TITLE:${title ? title.replace(',', '\\\\,') : ''}\\n"\n        s << "TEL;TYPE=work,voice,pref:${phone}\\n"\n        s << "TEL;TYPE=cell,voice:${cellphone}\\n"\n        s << "EMAIL;type=internet,pref:${email}\\n"\n        s << "ADR;TYPE=work,postal,pref:;;${address};${city};${state};${postalCode};${country}\\n"\n        def timestampFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")\n        s << "REV:${timestampFormat.format(lastUpdated ?: dateCreated)}\\n"\n        s << "END:VCARD\\n"\n        return s.toString()\n    }\n}\n
\n

Now it's easy to render a QRCode of the contact information.\nThis QRCode can be scanned with a smartphone and imported as a contact.

\n
<qrcode:image height="150" text="${person.vcard}" alt="${person.fullName} ${person.address} ${person.city}"/>\n
\n

Changes

\n

Version 0.9: Prevent DoS attempts using large size/width values.

\n

Version 0.8: Grails 3 support.

\n

Version 0.7: Upgraded zxing dependency to 3.2.0.

\n

Version 0.6: Upgraded pngj dependency to 2.1.0.

\n" }, { "bintrayPackage": { "name": "quartz", "repo": "plugins", "owner": "grails", "desc": "Grails quartz plugin", "labels": [ "quartz", "scheduling" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails/grails-quartz/issues", "latestVersion": "3.0.0", "updated": "2024-04-04T01:05:36.000Z", "systemIds": [ "org.grails.plugins:quartz" ], "vcsUrl": "https://github.com/grails/grails-quartz" }, "documentationUrl": "https://grails.github.io/grails-quartz/latest/", "mavenMetadataUrl": "https://repo1.maven.org/maven2/org/grails/plugins/quartz/maven-metadata.xml", "readme": null }, { "bintrayPackage": { "name": "quartz-config-scheduler", "repo": "grails-plugins", "owner": "9ci", "desc": "Quartz Config Scheduler - Allow creating quartz job from configuration", "labels": [ "quartz", "scheduling" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/yakworks/quartz-config-scheduler/issues", "latestVersion": "4.0.0", "updated": "2020-10-31T05:17:26.442Z", "systemIds": [ "org.grails.plugins:quartz-config-scheduler" ], "vcsUrl": "https://github.com/yakworks/quartz-config-scheduler" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

\"CircleCI\"\n\"9ci\"\n\n\"forthebadge\"\n\n\"forthebadge\"

\n

Install

\n

grails 4

\n
compile "org.grails.plugins:quartz-config-scheduler:4.0.0"\n
\n

grails 3+

\n
compile "org.grails.plugins:quartz-config-scheduler:2.0.0"\n
\n

Quartz config scheduler

\n

The plugin builds on top of quartz grails plugin and makes it possible to schedule quartz job on the fly from configuration.

\n

Quickstart

\n

Enable grails.plugin.quartz.autoStartup = true

\n

And then schedule a closure job as shown below.

\n

File application.groovy or an external configuration file.

\n
import org.quartz.Trigger\nimport org.quartz.Scheduler\nimport org.springframework.context.ApplicationContext\nimport grails.plugin.quartzconfigscheduler.ClosureJob\nimport org.quartz.JobExecutionContext\nimport org.quartz.TriggerBuilder\n\ngrails.plugin.quartz.jobSetup.testJob = { Scheduler scheduler, ApplicationContext context ->\n    \n    Trigger trigger = TriggerBuilder.newTrigger().withIdentity("closureJobTrigger")\n        .withSchedule(\n            simpleSchedule()\n            .withIntervalInMilliseconds(10)\n            .withRepeatCount(2)\n        ).startNow().build()\n        \n    Map jobParams = [param1:value1]\n    ClosureJob.schedule(trigger, jobParams) { JobExecutionContext jobCtx ->\n        println "Job executed"\n    }    \n\n}\n\n
\n

Configuration

\n\n

Scheduling jobs

\n

Plugin provides two job classes to setup jobs from configuration. ClosureJob and SpringBeanJob\nPlugin looks for configuration key grails.plugin.quartz.jobSetup and each child key of it is considered as a job setup\nIt must be a closure, the closure gets executed on application startup and is passed two parameters Scheduler and ApplicationContext

\n

ClosureJob

\n

ClosureJob provides one static method schedule which takes a trigger, Map of job params and a closure and schedules the quartz job.\nThe closure is executed each time the job is triggered. The JobExecutionContext is passed to the closure as argument.

\n

Example

\n
\nTrigger trigger //build trigger as per the need\nClosureJob.schedule(trigger, jobParams) { JobExecutionContext jobCtx ->\n        println "Job executed"\n\n}   \n
\n

SpringBeanJob

\n

SpringBeanJob can be used to schedule a job which will invoke a specified method on a configured spring bean.\nThe SpringBeanJob provides a static method which takes Trigger, spring bean name, method name and arguments to pass to the method as parameters\nand calls the method on the spring bean with specified arguments every time the job is triggered.

\n

Example\nimport grails.plugin.quartzconfigscheduler.SpringBeanJob

\n

File: application.groovy

\n
\nTrigger trigger //build trigger as per the need\nSpringBeanJob.schedule(trigger, "myService", "testMethod", "testArg")\n\n\nclass MyService {\n\n    void testMethod(String arg) {\n        println "Method is executed with arg $arg"    \n    }\n\n}\n\n
\n" }, { "bintrayPackage": { "name": "queuekit", "repo": "maven", "owner": "vahid", "desc": "Queuekit is a plugin for grails which uses TaskExecutor with Spring Events for grails 2 and for grails 3 using default `Reactor` events to manage concurrent submitted reports.", "labels": [ "reporting", "scheduling", "queue" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/vahidhedayati/grails-queuekit-plugin/issues", "latestVersion": "1.10", "updated": "2016-11-02T21:53:15.054Z", "systemIds": [ "org.grails.plugins:queuekit" ], "vcsUrl": "https://github.com/vahidhedayati/grails-queuekit-plugin" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

queuekit

\n

Side note - similar / related projects

\n\n

Queuekit is a plugin for grails which uses TaskExecutor with Spring Events for grails 2 and for grails 3 using

\n

default Reactor events to manage concurrent submitted reports.You can use it for your own custom reporting needs or\nsimply combine it with grails export plugin to queue export requests.

\n
At work we face a scenario where reports and core application are integrated and even if separated they would
\n

still hit the same database.

\n
The reports are typically rendered through response as a file stream and saved to user's desktop.
\n
At some periods of the day the application runs slow, we think due to people running reports concurrently.
\n

Without going into further complexity of database, application and reporting system. A cure would be to limit the amount\nof concurrent reports that can run and sort reports based on a priority system allowing (HIGHER: Speedier ones through\nover LOWER: Calculations would suggest it will take long per report basis)

\n
Queuekit plugin incorporates TaskExecutor ArrayBlocking / LinkBlocking and PriorityBlocking.
\n

It also enhances on PriorityBlocking with a new custom method called EnhancedPriorityBlocking.

\n
Define queue limit which in turn limits concurrent usage of all users.
\n
Typical request on demand report system will change to background queued reports system. Choose the
\n

best blocking method for your queues.

\n
Both Priority and EnhancedPriority allow queue items to have a default or on the fly priority.
\n
EnhancedPriorityBlocking is more costly and launches addition threads per job but all in aid of actually being
\n

able to kill a live running IO task.

\n
When master task or live running task is cancelled. The underlying thread is cancelled. This gives you the
\n

feature to cancel live background threaded tasks.

\n
If you run reports in such a manner, read on since with a minor tweak and the help of this plugin you can easily
\n

convert those reports to background queued tasks that you then define limitation over.

\n

1. Installation:

\n

Grails 3:

\n
compile "org.grails.plugins:queuekit:1.10"\n
\n
source |
\n

demo

\n

Grails 2:

\n
compile ":queuekit:1.5"\n
\n
source |
\n

demo

\n

2.Configuration

\n

The configuration provided would be added to Config.groovy on grails 2 and application.groovy in grails 3.

\n

####Videos

\n
Video 1:- grails queuekit plugin part 1 : Why you would use this plugin?
\n
Video 1:- grails queuekit plugin part 1.5 : Combine grails export plugin with queuekit so export requests are queued
\n
Video 2:- grails queuekit plugin part 2 : Configuration walkthrough
\n
Video 3:- grails queuekit plugin part 3 : Demonstrating cancellation of live threadExecutor Threads
\n
Video 4:- grails queuekit plugin part 4 : Binding plugin with your grails application security
\n
Video 5:- grails queuekit plugin part 5: Preserving a running queue slot for defined priority or above
\n

Video Boxset (all of above)

\n

3.Information

\n

=====

\n

Provides a variety of methods managing your queue:

\n
\n
    \n
  1. ArrayBlockingQueue - This is the most basic and provided are database functionality to manage the queue for you\nArrayBlockingQueue has no mechanism to manage incoming threads, it will take on as much as available and beyond that\nreject them. Additional steps have been added to capture / re-queue those that exhaust the queue and to manually check\nthe queue upon completion of last task.
  2. \n
\n
\n
\n
    \n
  1. LinkedBlockingQueue - This manages the queue automatically\nLinkedBlockingQueue is the next phase up, Since it manages the queue for you. If you have 3 maximum threads and fire 5.\n2 will wait until the first 2 are done and then their picked up. Queue is processed and limited to items as they arrive.
  2. \n
\n
\n
\n
    \n
  1. PriorityBlockingQueue - This manages the queue automatically and also attempts to run concurrent requests with a priority.\nPriorityBlockingQueue by default provides a mechanism to manage queue items according to each items priorities.
  2. \n
\n
\n
\n
    \n
  1. EnhancedPriorityBlockingQueue - This manages the queue automatically and also attempts to run concurrent requests\nwith a priority. PriorityBlockingQueue by default provides a mechanism to manage queue items according to each items priorities.\nIt also binds a new thread task to an inner thread. This means you can also cancel a live running thread.\nWhen a cancel request is issued. The main running thread also kills off the inner thread that is the running task.\nThis required further concurrentHashMaps to track / remove elements.
  2. \n
\n
\n

With both PriorityBlocking and EnhancedPriorityBlocking which was really my own additional work around PriorityBlocking,

\n

The priority itself is defined by you in your Config.groovy depending on the name given to it.\nThere is also an additional hook that you can add to all/some of your reports that will go off and look at custom\nparameters provided by the report and decide if it should lower/higher the default config priority.\nAn example for this is also provided. The policy as to how it decides is entirely based on what works for you.\nYou could use the example to expand on your business logic.

\n
Must outline the topics covered in point 4 EnhancedPriority are all very experimental,
\n

it's the end ambition/desire to achieve all that without any side effects. I think you may find odd behaviour.\nYour input / enhancements are most welcome.

\n

You can configure the following:

\n
reportThreads=3\npreserveThreads = 1\npreservePriority = Priority.MEDIUM\n
\n
If you have 3 threads and 6 LOW Priority reports launched
\n

If after (reportThreads - preserveThreads) = 3 - 1 = 2 (So only 2 would run at most at any time of LOW Priority)

\n

This means all those below Priority.MEDIUM will have a spare slot to run within. In short an fast lane left open always\nfor those below medium and 2 slow lanes. You should be able to configure 6 report

\n

With admin rights you can:

\n

> Change a priority of a queued report from the main listing screen.

\n

But beyond that when a report is queued you can click on report item and choose change priority. If it was LOW and set\nby Config or override hook you now as the human can set it to be a higher priority which will take effect when next\nthread becomes available.

\n

> Increase / Decrease (override Config values of) reportThreads / preserveThreads and preservePriority.

\n

This means you can on the fly increase or decrease and change preservePriority group from the main report screen.\nThe changes are only for runtime. Meaning upon restart the defaults from Config.groovy or if not defined what\nplugin thinks is best is used.

\n

> Shutdown ThreadExecutor

\n

No idea why you want to do this unless you are testing in worst case scenario with intentions of testing\nuseEmergencyExecutor=false or manualDownloadEnabled=true

\n

> Control maximum running time before killing a running task and canelling it.

\n

configure killLongRunningTasks=300 where 300 = 5 minutes in seconds. Provide the time in seconds you wish to wait\nbefore the taskExecutor sechedule is killed off. This only works for EnhancedPriorityBlockingExecutor and when it\nattempts to pickup the next thread, it checks running task of existing threads.\nIf any match your set limit and beyond they are killed and set to status Cancelled

\n

With Configuration you can:

\n

> Configure report time highlight

\n

In this example if report takes:

\n
\n

over 01:10:02 (1 hour 10 minutes and 2 seconds) it will highlight in blue\nover 00:01:05 (1 minute and 5 seconds) it will highlight in orange\nover 00:00:12 (12 seconds) it will highlight in html colour code: #FFFFAA

\n
\n
   durationThreshHold = [\n\t\t[hours: 1, minutes: 10, seconds: 2, color: 'blue'],\n\t\t[minutes: 1, seconds: 5, color: 'orange'],\n\t\t[seconds: 12, color: '#FFFFAA']\n\t]\n
\n

> Configure a backup Executor for when / if main Executor is down

\n

When tasks go into rejection it is typically due to Executor having issues. This is all true for all Executor\ntypes provides besides ArrayBlocking.\nSo this feature is available for all besides ArrayBlocking. Since ArrayBlocking has no queue mechanism and is managed\nby plugin DB lookups. It automatically puts a new task in rejection if over limit running. Therefore we capture those\nand re-queue them in this case. For all other cases if you enable\nuseEmergencyExecutor=true This will tell the plugin to fall over to a single executor and launch a schedule of the\nuser request. This is all transparent to the end user and happens in the back-end. It will throw errors in the log.\nAll the rules of priorities goes out of the window and there are no limitations as many requests made is as many\nthreads launched. It keeps business flowing whilst a fix / resolution is found I guess.

\n

If main Executor is shutdown - due to how it is wired - (behaving like a service) it needs an application restart\nfor it to reset. Ideas welcome, some comments in EnhancedPriorityBlockingExecutor in regards to this.

\n

> Configure a backup of a backup or disable backup Executor and fall back to manualDownload

\n

Like above if tasks go into rejection, if you have configured backup executor and even that appears to be shutdown -\nwhich would be strange since the backup is a single executor launched per request. Either way, you can also set this\nto true manualDownloadEnabled=true in your Config.groovy.

\n

This again is transparent to the end user, but if all of above has failed it will actually launch a new single\nrunnable task to execute the task, the report is treated like all of above, it is captured in report listing, shows\nthat it is running and completed and is also timed. But has totally bypassed all of the threadExecutors and just\nlaunched as a thread within application.

\n

This also behaves like all of above meaning the end user will get a prompt report has been triggered and if trained to\ndo all ove above they would go to the normal listing screen and wait for it to complete.

\n

If you wanted to make this fail over behave like a real download, you could refer to ReportDemoController index\naction which has the following:\n(It makes the user wait on the screen whilst the manual thread goes through the process of being created. When it has a\nfile, it redirects to download page like they would have if they had clicked on a live report download action.

\n

4. Additional simplification / explanation

\n

This plugin is from a concept I put together for work and will convert the process of user report interaction from one of :

\n

Click on a report - or define report criteria and click download

\n

If the process is to then go off and get data produce a CSV,XLS,TSV,DOC,PDF of some form and you are using your controller request mechanism\nto deliver file through a stream.

\n

If above describes your scenario then as you are probably well aware, as database/user-base grows and more reports are\nrequested. Specially concurrent requests by many users can have an impact on your application performance.

\n

This plugin will be able to change that process and limit to concurrent threads as well as provide a queueing / user\nreport interface. Since the jobs are converted to background tasks the files are produced when system has completed\nand user has to check another interface rather than on demand file generated on the fly as they clicked save/download.

\n

The process to convert your existing reports should be really kept to a minimal so long as Controller was used to\ngenerate file from some result set that came back from some service. The only minor change is where you\ndefined request type and out and filename. These segments can be stripped out and rest will be near\nenough what you had :

\n

Examples

\n

Binding queuekit with grails export plugin

\n

Most importantly pay attention to bufferedWriterTypes configuration ensure you have removed CSV and csv from it. If you\nare going to use this plugin for working with export plugin. The export plugin uses a different way to export csv compared\nto how you would normally through a controller as described further down under manual reports.

\n

You can use this plugin in conjunction with the export plugin to essentially change the mechanism from files produced\nas requested to user requests for export plugin being quueed through queuekit.

\n

Please feel free to browse through the grails 3 demo site which has all of this in place, I will show the more\nadvanced version since it is probably most feasible.

\n

You have installed/been using export plugin, you have configured the required addition in the controller to send\nreport to exportService.

\n

I installed the plugin, created a domain class generated controllers and views and then amended the call to\nexportService to :\nqueueReportService.buildReport(reportName,userId , locale, params)

\n

Change that to this

\n
\n    //def exportService\n    def myUserService\n    def queueReportService\n\n    def index(Integer max) {\n        params.max = Math.min(max ?: 10, 100)\n        String format=params.f  ?: params.extensions ?: 'html'\n        if(format && format != "html"){\n            def locale = RequestContextUtils.getLocale(request)\n            def userId = myUserService.currentuser\n            String reportName = 'exportPluginAdvanced'\n            /**\n             * ! -- IMPORTANT\n             * In order to let this dynamic exportPluginAdvancedReportingService pickup the correct domainClass\n             * We must send an additional params as part of reports calls and bind in the actual domainClass we would be listing\n             * just like shown here\n             *\n             */\n            params.domainClass=TestAddress.class\n\n            log.debug "Sending task as default priority to queueReportService instead of exportService.export"\n            //def queue = queueReportService.buildReport(reportName,userId , locale, params,Priority.HIGH,ReportsQueue.PRIORITYBLOCKING)\n            def queue = queueReportService.buildReport(reportName,userId , locale, params)\n\n            flash.message = g.message(code: 'queuekit.reportQueued.label', args: [reportName, queue?.id])\n\n            /**\n             * How you would normally export using Export plugin\n             * Changed to above to go through queuekit plugin and queue request instead\n             *\n             * Take a look at ExportPluginAdvancedReportingService to see how you can do the same\n             *\n             */\n            // response.contentType = grailsApplication.config.grails.mime.types[format]\n            // response.setHeader("Content-disposition", "attachment; filename=books.${params.extension}")\n            // exportService.export(format, response.outputStream,TestExport.list(params), [:], [:])\n        }\n        respond TestAddress.list(params), model:[testAddressCount: TestAddress.count()]\n    }\n
\n

Now with this in place I will need to create a new service called ExportPluginAdvancedReportingService:

\n
package test\n\n\nimport grails.util.Holders\nimport org.grails.plugin.queuekit.ReportsQueue\nimport org.grails.plugin.queuekit.reports.QueuekitBaseReportsService\n\nclass ExportPluginAdvancedReportingService extends QueuekitBaseReportsService {\n\n\tdef exportService\n\n\tdef runReport(ReportsQueue queue,Map params) {\n\t\trunReport(queue,[something:'aa'],params)\n\t}\n\t// This doesn't matter so much so long as it meets the Type that is not of\n\t// config value of config.bufferedWriterTypes\n\t// Since it needs to call the other method in QueuekitBaseReportsService\n\t// Actual fileName extension is overriden right at the very bottom of this\n\t// class in getReportName by bean.extension (this ensures file is correctly labelled\n\tString getReportExension() {\n\t\treturn 'xls'\n\t}\n\n\tdef actionInternal(ReportsQueue queue,out,bean, queryResults,Locale locale) {\n    \t\tactionReport1Report(queue,out,bean,queryResults)\n    \t}\n\n\n    \t/**\n    \t *\n    \t *\n    \t * @param out -> Where out is provided by plugin\n    \t * @param bean ->Where bean is your actual user params from the front end screen\n    \t * @param queryResults -> QueryResults would be what would be produced by your code\n    \t * \t\t\t\tIn the case of this we are setting it to [something:'aa']\n    \t * \t\t\t\tabove. This then will continue working and hit this block\n    \t * \t\t\t\twhich will carry out real export service task at hand.\n         */\n\n    \tprivate void actionReport1Report(queue,out,bean,queryResults) {\n    \t\tString format=bean.f ?: 'html'\n    \t\tif(format && format != "html"){\n    \t\t\tlog.debug "Params received  ${bean.f} ${bean.extension} "\n    \t\t\tdef domain= bean.domainClass\n    \t\t\ttry {\n    \t\t\t\tif (domain) {\n    \t\t\t\t\tprintln "got Domain ${domain}"\n    \t\t\t\t\t//\tdef domainClass = Holders.grailsApplication?.domainClasses?.find { it.clazz.simpleName == uc(domain) }?.clazz\n    \t\t\t\t\tdef domainClass = Holders.grailsApplication.getDomainClass(domain)?.clazz\n    \t\t\t\t\tif (domainClass) {\n    \t\t\t\t\t\tprintln "we have a real domainClass ${domainClass}"\n    \t\t\t\t\t\tdomainClass.withTransaction {\n    \t\t\t\t\t\t\tMap formatters=[:]\n    \t\t\t\t\t\t\tMap parameters=[:]\n    \t\t\t\t\t\t\tswitch (domain) {\n    \t\t\t\t\t\t\t\tcase 'testing.TestAddress':\n    \t\t\t\t\t\t\t\t\tprintln "custom testAddress stuff here"\n    \t\t\t\t\t\t\t\t\t//formatters=[:]\n    \t\t\t\t\t\t\t\t\t//parameters=[:]\n    \t\t\t\t\t\t\t\t\t//bean.something=SomethingElse\n    \t\t\t\t\t\t\t\t\tbreak\n    \t\t\t\t\t\t\t\tcase 'testing.TestAttribues':\n    \t\t\t\t\t\t\t\t\tprintln "custom testAttributes stuff here"\n    \t\t\t\t\t\t\t\t\t//What would you like to do\n    \t\t\t\t\t\t\t\t\t//formatters=[:]\n    \t\t\t\t\t\t\t\t\t//parameters=[:]\n    \t\t\t\t\t\t\t\t\tbreak\n    \t\t\t\t\t\t\t}\n    \t\t\t\t\t\t\texportService.export(format, (OutputStream) out, domainClass.list(bean),formatters,parameters)\n    \t\t\t\t\t\t}\n    \t\t\t\t\t}\n    \t\t\t\t}\n    \t\t\t} catch (Exception e) {\n    \t\t\t\tsuper.errorReport(queue,bean)\n    \t\t\t}\n    \t\t}\n\n\t/*\n\t *\n\t * Overriding how QueuekitBaseReportsService names it here\n\t */\n\tString getReportName(ReportsQueue queue,bean) {\n\t\treturn "ExportPlugin-${queue.id}.${bean.extension?:reportExension}"\n\t}\n\n}\n\n
\n

That's it, the user reports will now be queued through the queuekit plugin,\nYou can see export feature is called in the ExportPluginAdvancedReportingService.\nThe code in the controller can be copied from controller to controller.\nJust pay attention to: (Ensure you are passing in correct domainClass that you will use in the sharedExport service.

\n
 /**\n             * ! -- IMPORTANT\n             * In order to let this dynamic exportPluginAdvancedReportingService pickup the correct domainClass\n             * We must send an additional params as part of reports calls and bind in the actual\n             * domainClass we would be listing\n             * just like shown here\n             *\n             */\n            params.domainClass=TestAddress.class\n
\n

Manual Reports using plugin with your own methods of producing reports

\n

Apache-poi XLS files - manual report

\n

Check out grails queuekit demo site for grails 3. Follow the example to see how I got it to work\nAll very similar to instructions below besides that it is using custom libraries to produce the output. (different file types to standard csv/tsv described below)

\n

Examples demonstrated on

\n

org.grails.plugin.queuekit.examples.ReportDemoController

\n

``

\n

Assuming you have:

\n
response.setHeader 'Content-type','text/plain; charset=utf-8'\nresponse.setHeader "Content-disposition", "attachment; filename=index.tsv"\ndef out = response.outputStream\ndef queryResults=tsvService.runParams(params)\n\tout << 'name\\t'\n\tout << "testing"\n\tout << '\\rtext\\t'\n\tout << "testing text"\n\tout << '\\r'\n\tqueryResults?.each{field->\n\t\tout << field.id << '\\t'\n\t\tout << field.text << '\\t'\n\t\tout << '\\r'\n\t}\nout.flush()\nout.close()\n
\n

If you change to be like this:

\n
def controllerCall() {\n  response.setHeader 'Content-type','text/plain; charset=utf-8'\n  response.setHeader "Content-disposition", "attachment; filename=index.tsv"\n  def out = response.outputStream\n  def queryResults=tsvService.runParams(params)\n  actionReport(out,queryResults,params)\n}\nprivate actionReport(out,queryResults,params) {\n  out << 'name\\t'\n  out << params.report\n  out << '\\rtext\\t'\n  out << params.sample\n  out << '\\r'\n  queryResults?.each{field->\n\tout << field.id << '\\t'\n\tout << field.text << '\\t'\n\tout << '\\r'\n  }\n  out.flush()\n  out.close()\n}\n
\n

Then you are half way there, in principal the same thing would be put in to your service that would be in the action\nreport. The plugin handles out so there will be no need to define response or out variables. So all of above would become:

\n
def controllerCall() {\n\tdef locale = RequestContextUtils.getLocale(request)\n\tdef userId = queuekitUserService.currentuser\n\tString reportName = 'paramsExample'\n\n\t/*\n\t * these are your own params really\n\t */\n\tparams.report='Params examples'\n\tparams.sample='Some sample text'\n\t\t\n\t//No queue defined - by default Priority\n\tdef queue = queueReportService.buildReport(reportName,userId , locale, params)\n\tflash.message = g.message(code: 'queuekit.reportQueued.label', args: [reportName, queue?.id])\n}\n
\n

Then we create a service called ParamsExampleReportingService

\n
package org.grails.plugin.queuekit.examples.reports\n\nimport org.grails.plugin.queuekit.ReportsQueue\nimport org.grails.plugin.queuekit.reports.QueuekitBaseReportsService\n\n\nclass ParamsExampleReportingService extends QueuekitBaseReportsService {\n\n\tdef tsvService\n\t\n    /*\n\t * Must be declared gives you params \n\t * You must run your service to get back the results\n\t * Push results params and queue into runReport as show\n\t */\n\tdef runReport(ReportsQueue queue,Map params) {\n\t\tdef queryResults = tsvService.runParams(params)\n\t\trunReport(queue,queryResults,params)\n\t}\n\n    /*\n     * You must define this as shown. Plugin will provide you at this point\n     * with out. Push out queryResults and bean = your original params back into \n     * your own custom method which like shown above iterates through your list\n     * and pushes into out\n     */\n\tdef actionInternal(ReportsQueue queue,out,bean, queryResults,Locale locale) {\n\t\tactionReport1Report(out,bean,queryResults)\n\t}\n\n\tprivate void actionReport1Report(out,bean,queryResults) {\n\t\tout << 'name\\t'\n\t\tout << bean.report\n\t\tout << '\\rtext\\t'\n\t\tout << bean.sample\n\t\tout << '\\r'\n\t\tqueryResults?.each{field->\n\t\t\tout << field.id << '\\t'\n\t\t\tout << field.text << '\\t'\n\t\t\t//This will also work like in your controller\n\t\t\t//out << "${g.message(code:'some.code')}"\n\t\t\tout << '\\r'\n\t\t}\n\t\tout.flush()\n\t\tout.close()\n\t}\n}\n
\n

That now queues the report requests when someone clicks controllerCall and the report can be seen Here

\n

You can also use this technology for any other type of files you were generating on the fly in a controller so for example apache-poi

\n
String filename = 'Report3Example.xls'\n\tHSSFWorkbook wb = new HSSFWorkbook()\n\tHSSFSheet sheet = wb.createSheet()\n\t....\n\ttry {\n\t\t\n\t\t// When copying your method over to your new Service\n\t\t// as already mentioned out is already provided by plugin \n\t\t// the below 4 lines should not be provided in the new service call\n\t\t// everything else is identical\n\t\tresponse.setContentType("application/ms-excel")\n\t\tresponse.setHeader("Expires:", "0") // eliminates browser caching\n\t\tresponse.setHeader("Content-Disposition", "attachment; filename=$filename")\n\t\tOutputStream out = response.outputStream\n\t\t// End of no longer required - when converted to plugin service method \n\t\twb.write(out)\n\t\tout.close()\n\t} catch (Exception e) {\n\t}\n
\n

Would be changed to like per above:

\n
def controllerCall() {\n\tdef locale = RequestContextUtils.getLocale(request)\n\tdef userId = queuekitUserService.currentuser\n\tString reportName = 'xlsExample'\n\n\t/*\n\t * these are your own params really\n\t */\n\tparams.report='Params examples'\n\tparams.sample='Some sample text'\n\t\t\n\t//No queue defined - by default Priority\n\tdef queue = queueReportService.buildReport(reportName,userId , locale, params)\n\t//You can provide further options look up ReportDemoController to see more examples\n\t//def queue = queueReportService.buildReport(reportName,userId , locale, params,Priority.HIGH,ReportsQueue.PRIORITYBLOCKING)\n\tflash.message = g.message(code: 'queuekit.reportQueued.label', args: [reportName, queue?.id])\n}\n
\n

Then we create XlsExampleReportingService

\n
package org.grails.plugin.queuekit.examples.reports\n\nimport org.grails.plugin.queuekit.ReportsQueue\nimport org.grails.plugin.queuekit.reports.QueuekitBaseReportsService\n\n\nclass XlsExampleReportingService extends QueuekitBaseReportsService {\n\n\n\t\n\tdef tsvService\n\t\n\t/*\n\t * We must define the report type file extension\n\t * default is tsv this being XLS needs to be defined\n\t * \n\t */\n\tString getReportExension() {\n\t\treturn 'xls'\n\t}\n\t\n\t\n\t/**\n    \t * This overrides the default priority of the report set by\n    \t * QueuekitBaseReportsService\n    \t *\n    \t * By default it is either as per configuration or if not by default\n    \t * LOW priority.\n    \t *\n    \t * At this point you can parse through your params and decide if in this example\n    \t * that the given range fromDate/toDate provided is within a day make report\n    \t * HIGHEST\n    \t * if within a week HIGH and so on\n    \t *\n    \t * This priority check takes place if you are using\n    \t * standard standardRunnable = false if your report default type is\n    \t * EnhancedBlocking\n    \t * if disableUserServicePriorityCheck=false and standardRunnable = true\n    \t * then it should use the priority method very similar to this in\n    \t *\n    \t * queuekitUserService. This is the service you are supposed to extend\n    \t * and declare as a bean back as queuekitUserService.\n    \t *\n    \t * Then you can control priority through this service call and a more\n    \t * centralised control can be configured/setup.\n    \t *\n    \t */\n    \tPriority getQueuePriority(ReportsQueue queue, Map params) {\n    \t\tPriority priority = queue.priority ?: queue.defaultPriority\n    \t\tif (params.fromDate && params.toDate) {\n    \t\t\tDate toDate = parseDate(params.toDate)\n    \t\t\tDate fromDate = parseDate(params.fromDate)\n    \t\t\tint difference = toDate && fromDate ? (toDate - fromDate) : null\n    \t\t\tif (difference||difference==0) {\n    \t\t\t\tif (difference <= 1) {\n    \t\t\t\t\t// 1 day everything becomes HIGH priority\n    \t\t\t\t\tpriority = Priority.HIGH\n    \t\t\t\t} else if  (difference >= 1 && difference <= 8) {\n    \t\t\t\t\tif (priority == Priority.HIGHEST) {\n    \t\t\t\t\t\tpriority = Priority.HIGH\n    \t\t\t\t\t} else if (priority >= Priority.MEDIUM) {\n    \t\t\t\t\t\tpriority = priority.value.previous()\n    \t\t\t\t\t}\n    \t\t\t\t} else if  (difference >= 8 && difference <= 31) {\n    \t\t\t\t\tif (priority <= Priority.HIGH) {\n    \t\t\t\t\t\tpriority = Priority.MEDIUM\n    \t\t\t\t\t} else if (priority >= Priority.LOW) {\n    \t\t\t\t\t\tpriority = priority.next()\n    \t\t\t\t\t}\n    \t\t\t\t} else if  (difference >= 31 && difference <= 186) {\n    \t\t\t\t\tif (priority >= Priority.MEDIUM && priority <= Priority.HIGHEST) {\n    \t\t\t\t\t\tpriority = priority.next()\n    \t\t\t\t\t} else if (priority >= Priority.LOW) {\n    \t\t\t\t\t\tpriority = priority.previous()\n    \t\t\t\t\t}\n    \t\t\t\t} else if  (difference >= 186) {\n    \t\t\t\t\tif (priority <= Priority.LOWEST) {\n    \t\t\t\t\t\tpriority = priority.previous()\n    \t\t\t\t\t} else if (priority >= Priority.LOW) {\n    \t\t\t\t\t\tpriority = priority.next()\n    \t\t\t\t\t}\n    \t\t\t\t}\n    \t\t\t}\n    \t\t\tlog.debug "priority is now ${priority} was previously ${priority} difference of date : ${difference}"\n    \t\t}\n    \t\treturn priority\n    \t}\n\t\n\t/*\n\t * \n\t * Overriding how QueuekitBaseReportsService names it here\n\t * Take a look at CsvExampleReportingService where a more \n\t * complex example is provided that defines filename based on \n\t * a value within bean - the report was used\n\t * for multiple different reports - each doing something slightly \n\t * different but using same input bean ..\n\t */\n\tString getReportName(ReportsQueue queue,bean) {\n\t\treturn "MyLovelyReport-${queue.id}.${reportExension}"\n\t}\n\n\n    \n\tdef runReport(ReportsQueue queue,Map params) {\n\t\tdef queryResults = tsvService.runParams(params)\n\t\trunReport(queue,queryResults,params)\n\t}\n\n\tdef actionInternal(ReportsQueue queue,out,bean, queryResults,Locale locale) {\n\t\tactionReport1Report(out,bean,queryResults)\n\t}\n\n\tprivate void actionReport1Report(out,bean,queryResults) {\n\t\tHSSFWorkbook wb = new HSSFWorkbook()\n\t\tHSSFSheet sheet = wb.createSheet()\n\t\t//Do your stuff you are doing with out\n\t\tHSSFRow row=sheet.createRow(counter)\n\t\tCell cell1 = row.createCell(i)\n\t\t\tcell1.setCellValue("")\n\t\t\tcell1.setCellStyle(headingStyle)\n\t\t...\n\t\t// finally the above block you had above becomes much simpler\n\t\t// like this:\n\t\t// out is then taken care of by plugin\n\t\ttry {\n\t\t\twb.write(out)\n\t\t\tout.close()\n\t\t} catch (Exception e) {\n\t\t}\n\t\t\t\n\t\t\n\t}\n}\n
\n

Beans that bind to other objects

\n

Take a look at\norg.grails.plugin.queuekit.examples.ComplexBindedBean and read through it to understand how to bypass it

\n

Other useful information

\n
\n

queuekitUserService def userId = queuekitUserService.currentuser

\n
\n

This is a userService that exists within this plugin, you should override this as per example site and feed in your\nreal user/userId/userLocale/permission values in from your own site.

\n
\n

reportName String reportName = 'tsvExample1'

\n
\n

This is really as important as it gets, ensure you use proper class naming convention so no +_&*^!\ufffd\ufffd\ufffd\ufffd$%^ characters no\nspace etc just normal alphabet as if you were naming a domain class.\nCreate a new service called

\n
\n
${name}ReportingService TsvExample1ReportingService
\n
\n

This service must extend QueuekitBaseReportsService.

\n

Binding application security with the plugin

\n

Under the grails 3 demo site, spring security got installed a new\nservice called MyUserService which extends QueuekitUserService and overrides the default actions of the plugin to return\nuserId if user is a super user and so forth.

\n

The service then takes over QueuekitUserService the test site's grails-app/init/test.queuekit3/Application.groovy

\n
class Application extends GrailsAutoConfiguration {\n    Closure doWithSpring() {\n        { ->\n            queuekitUserService(test.MyUserService)\n        }\n    }\n    ///....\n
\n

Quartz scheduling clean up

\n

If you are running quartz, create a task probably running daily that calls

\n
def queueReportService\n...\n\nqueueReportService.deleteReportFiles()\n
\n

Bootstrap task to re-schedule old queued task pre-application shutdown

\n

In your Bootstrap.groovy declare

\n
//Inject the service\ndef queuekitExecutorBaseService\n\n//Run this \nqueuekitExecutorBaseService.rescheduleRequeue()\n\n//Also ensure you have enabled in your Config.groovy/application.groovy\nqueuekit.checkQueueOnStart=true\n
\n" }, { "bintrayPackage": { "name": "queuemail", "repo": "maven", "owner": "vahid", "desc": "Queuemail plugin is a centralised email queueing system configurable for many providers all centrally controlled and limited to either daily limit or failures exceeding failureTolerance limit (in a row). By default all email's passing through are priority driven and configured by overall customService name. Two methods of priority queueing are provided BASIC and ENHANCED (default). Enhanced launches an additional thread for each running task and will attempt to kill any running process considered as stuck (if time taken exceeds killLongRunningTasks configuration period). ", "labels": [ "mail", "queue" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/vahidhedayati/grails-queuemail-plugin/issues", "latestVersion": "1.3", "updated": "2016-12-07T09:29:32.413Z", "systemIds": [ "org.grails.plugins:queuemail" ], "vcsUrl": "https://github.com/vahidhedayati/grails-queuemail-plugin" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Grails QueueMail plugin

\n

Side note - similar / related projects

\n\n

Queuemail plugin is a centralised email queueing system configurable for many providers all centrally controlled and limited to either daily limit or failures exceeding failureTolerance limit (in a row). By default all email's passing through are priority driven and configured by overall customService name. Two methods of priority queueing are provided BASIC and ENHANCED (default). Enhanced launches an additional thread for each running task and will attempt to kill any running process considered as stuck (if time taken exceeds killLongRunningTasks configuration period).

\n

Email's that arrive in queue are processed through priority rules, please refer to example configuration, each new service you create can be configured to have a specific priority. Higher ones run in preference of lower ones.

\n

Configure how many active concurrent email threads can run at any one time and how many\ncan wait in the queue to be served. Each email is then bound to the emailService that you create and within it you define\nthe configNames and limit. The configName will then need to be created in your applications Config.groovy/application.groovy\nand essentially contains the SMTP configuration required to connect through and send email's.

\n

The queueing system will use the first provided configuration for every email requested. If this first configName goes offline or\nwas configured incorrectly it will hit a threshold and plugin will mark configuration as inactive

\n

If an email send attempt fails the sole email is re-attempted until it reaches\nfailuresTolerated level. Once this happens current configName is marked as inactive and the next configName is attempted to deliver this email.\nAll new email's will now be going through second configName. The configName that was made inactive will automatically re-join active pool after either setPeriod of time or amount of queueId's passing through. Please refer to notes/configuration and specific segment on message exceptions below.

\n

Please check with your SMTP provider to ensure you are not violating any TOC's whilst attempting to keep within their set limits/boundaries and consequently/possibly having to switch accounts/providers.

\n

Please use this plugin responsibly

\n

1. Installation/Configuration:

\n

Grails 3: source configuration

\n
compile "org.grails.plugins:queuemail:1.3"\n
\n

Grails 2: source configuration

\n
compile ":queuemail:1.0"\n
\n

Basic service the defines SMTP configurations (that are binded to Config objects and limitations per day)

\n
class QueueMailExampleService extends QueueMailBaseService {\n\n\tdef configureMail(executor,EmailQueue queue) {\n\t\t/**\n\t\t * Contains a list of configuration names : daily limit for account\n\t\t * So mailConfigExample1 will bind to Config.groovy SMTP configuration\n\t\t * assuming it is google it may have 3000 daily limit \n\t\t * A listing is provided so it can fall over between list elements starting from top\n\t\t * working it's way down and when limit exceeds it will use the next element\n\t\t */\n\t\tdef jobConfigurations = [\n\t\t\t\t'mailConfigExample1': 2,\n\t\t\t\t'mailConfigExample2': 2,\t\t\t\t\n\t\t\t]\n        sendMail(executor,queue,jobConfigurations,QueueMailExampleService.class)\n\t}\n}\n
\n

Please configure {configName}.fromAddress as shown below. Please note when this is set the actual from address you\nprovide will become replyTo and from will be set as {configName}.fromAddress. If you do not provide this then\nnothing is changed.

\n

Now with queueMailExample service created, refer to SampleConfig.groovy add the relevant accounts to the\nconfiguration as shown to match with above names. In the most basic form if you add the following to your\nConfig.groovy or application.groovy

\n

Example configuration for grails 2

\n
\nqueuemail {\n\n\tmailConfigExample1 {\n\t\thost = "smtp.internal.com"\n\t\tport = 465\n\t\tusername = "USERA@internal.com"\n\t\tpassword = "PASSWORDA"\n\t\tprops = ["mail.debug":"true",\n\t\t\t"mail.smtp.auth":"true",\n\t\t\t"mail.smtp.socketFactory.port":"465",\n\t\t\t"mail.smtp.socketFactory.class":"javax.net.ssl.SSLSocketFactory",\n\t\t\t"mail.smtp.socketFactory.fallback":"false"]\n\t}\n\tmailConfigExample1.fromAddress="USERA@internal.com"\n\t\n\tmailConfigExample2 {\t\t\n\t  host = "external.smtp.com"\n\t  port = 465\n\t  username = "USERB@smtp.com"\n\t  password = "PASSWORDB"\n\t  props = ["mail.debug":"true",\n\t\t\t"mail.smtp.auth":"true",\n\t\t\t"mail.smtp.socketFactory.port":"465",\n\t\t\t"mail.smtp.socketFactory.class":"javax.net.ssl.SSLSocketFactory",\n\t\t\t"mail.smtp.socketFactory.fallback":"false"]\n\t}\n\tmailConfigExample2.fromAddress="USERB@smtp.com"\n}\t\n
\n

Example configuration for application.groovy on grails 3

\n

All the additional smtp configuration required whilst testing gmail (only under grails 3):

\n
import org.grails.plugin.queuemail.enums.QueueTypes\n\nqueuemail {\n\n\t//standardRunnable = true\n\temailPriorities = [\n\t\t\t\t\tdefaultExample:org.grails.plugin.queuemail.enums.Priority.REALLYSLOW\n\t]\n\n\t// This is an override of grails { mail { configuration method allowing many mail senders\n\n\t// The configuration for DefaultExampleMailingService has set this to be 2 email's\n\t// Meaning after 2 it will fall over to 2nd Configuration\n\n\texampleFrom="usera <userA@gmail.com>"\n\texampleTo="userA_ReplyTo <userA@gmail.com>"\n\n\tmailConfigExample1 {\n\t\thost = "smtp.internal.com"\n\t\tport = 587\n\t\tusername = "userA@internal.com"\n\t\tpassword = 'PASSWORD'\n\t\tprops = ["mail.debug":"true",\n\t\t\t\t "mail.smtp.user":"userA@internal.com",\n\t\t\t\t "mail.smtp.host": "smtp.internal.com",\n\t\t\t\t "mail.smtp.port": "587",\n\t\t\t\t "mail.smtp.auth": "true",\n\t\t\t\t "mail.smtp.starttls.enable":"true",\n\t\t\t\t "mail.smtp.EnableSSL.enable":"true",\n\t\t\t\t "mail.smtp.socketFactory.class":"javax.net.ssl.SSLSocketFactory",\n\t\t\t\t "mail.smtp.socketFactory.fallback":"false",\n\t\t\t\t "mail.smtp.socketFactory.port":"465"\n\t\t]\n\t}\n\tmailConfigExample1.fromAddress="USERAAA <userA@internal.com>"\n\n\tmailConfigExample2 {\n\t\thost = "smtp.gmail.com"\n\t\tport =587\n\t\tusername = "userB@gmail.com"\n\t\tpassword = 'PASSWORD'\n\t\tprops = ["mail.debug":"true",\n\t\t\t\t "mail.smtp.user":"userB@gmail.com",\n\t\t\t\t "mail.smtp.host": "smtp.gmail.com",\n\t\t\t\t "mail.smtp.port": "587",\n\t\t\t\t "mail.smtp.auth": "true",\n\t\t\t\t "mail.smtp.starttls.enable":"true",\n\t\t\t\t "mail.smtp.EnableSSL.enable":"true",\n\t\t\t\t "mail.smtp.socketFactory.class":"javax.net.ssl.SSLSocketFactory",\n\t\t\t\t "mail.smtp.socketFactory.fallback":"false",\n\t\t\t\t "mail.smtp.socketFactory.port":"465"\n\t\t]\n\t}\n\tmailConfigExample2.fromAddress="userBB<userB@gmail.com>"\n\n}\n
\n

QueueTestController used to show some of the examples below:

\n
\n            //BASIC TEXT\n\t\t\tLong userId = queueMailUserService.currentuser\n\t\t\tdef locale = RequestContextUtils.getLocale(request)\n\t\t\tEmail message = new Email(\n\t\t\t\t\tfrom: config.exampleFrom,\n\t\t\t\t\tto: [config.exampleTo],\n\t\t\t\t\tsubject: 'Subject',\n\t\t\t\t\ttext: 'Testing text message being sent via plugin'\n\t\t\t\t\t//html: params\n\t\t\t).save(flush: true)\n\t\t\tdef queue = queueMailApiService.buildEmail('queueMailExample', userId, locale, message)\n\n\n            //HTML TEMPLATE\n\t\t\t//This loads in a template and provides model which is the instance list for template\n\t\t\tdef paramsMap = [:]\n\t\t\tparamsMap.view = "/examples/testTemplate"\n\t\t\tparamsMap.model = [var1: "hello", var2: "there"]\n\t\t\t// Or Like this\n\t\t\t//Map paramsMap =  [view:"/examples/testTemplate",model:[var1:"hello", var2:"there"]]\n\n\t\t\tEmail message = new Email(\n\t\t\t\t\tfrom: config.exampleFrom,\n\t\t\t\t\tto: [config.exampleTo],\n\t\t\t\t\tsubject: 'Subject',\n\t\t\t\t\thtml: paramsMap\n\t\t\t)\n\t\t\tif (!message.save(flush: true)) {\n\t\t\t\tlog.error message.errors\n\t\t\t}\n\t\t\tdef queue = queueMailApiService.buildEmail('queueMailExample', userId, locale, message)\n\n\t\t\t//To Many recipients:\n\t\t\tLong userId = queueMailUserService.currentuser\n            def locale = RequestContextUtils.getLocale(request)\n            List\n            Email message = new Email(\n                    from: config.exampleFrom,\n                    //EITHER TO CC OR BCC\n                    to: [config.exampleTo, config.exampleTo, config.exampleTo, config.exampleTo],\n                    //FOR CC\n                    //cc:[config.exampleTo, config.exampleTo, config.exampleTo, config.exampleTo],\n                    //FOR BCC:\n                    //bcc: [config.exampleTo, config.exampleTo, config.exampleTo, config.exampleTo],\n                    subject: 'Subject',\n                    body: "<html>HTML text ${new Date()}</html>"\n            )\n            /**\n             * Above methods will fail to save, if you prefer you can use cleanTo cleanCc or cleanBcc\n             * same rules as above you must define one.\n             *\n             * If this method is used, the bad addresses are silently removed so object will save and\n             * only those with a good email address with be emailed (the last 2) in this example\n             *\n             *\n             * if you have port 25 open to make outgoing SMTP connections you could try enabling\n             *\n             * queuemail.smtpValidation=true\n             *\n             * This will attempt to check the email address of the recipient from the first MX bound\n             * to their email address. If valid then the email address is silently added.\n             *\n             * This is a pre-delivery confirmation (Experimental)\n             */\n\n            //message.cleanTo(['aa <aa@aa>','bb','cc','dd <dd@example.com>','ee <ee@example.com>'])\n            //message.cleanBcc(['aa <aa@aa>','bb','cc','dd <dd@example.com>','ee <ee@example.com>'])\n            //message.cleanCc(['aa <aa@aa>','bb','cc','dd <dd@example.com>','ee <ee@example.com>'])\n            if (!message.save(flush:true)) {\n                log.error message.errors\n            }\n            def queue = queueMailApiService.buildEmail(EXAMPLE_SERVICE,userId, locale, message)\n\n
\n

You store an Email in it's domain class. Then you call buildEmail which

\n

buildEmail(EXAMPLE_SERVICE, userId, locale, message)

\n
queueMailExample=maps up to QueueMailExampleMailingService (you create this) \nuserId=current userId\nlocale=current locale/user locale\nmessage=That email above you just saved\n
\n

Configuration for unreliable SMTP services

\n

Please visit above configuration links and read through the comments provided. At the very bottom it covers\nhost failures and how to limit / restrict host failures.

\n

Binding plugin with your application userbase

\n

Feel free to refer to queuekit plugin which may give more\ninsight into some of the additional values not covered such as binding your application with the plugin.\nThis way each user can only view their own email queue and admin or super users can view all as per default screen.\nThe queuekit plugin discusses queuekitUserService change that to queueMailUserService and any reference to how you\noverride it for this plugin.

\n

Many services for a given scenario

\n

You could have multiple services that have totally different sets of email configurations to pickup and depending on\nyour scenario then traffic the email to use serviceA or serviceB.

\n

Interface to queueing system

\n

The plugin also provides queueMail/listQueue controller / action that gives you an overview of how your\nemail's are being processed. It provides detailed information as to each emailService triggered and their underlying\nconfiguration status/health.

\n

Message errors / Exceptions and configuration activation

\n

1.3 introduced enums.MessageExceptions and monitor.ServiceConfigs.\nSMTP providers that trigger an exception depending on exception type can trigger actual provider(itself)\nto become inactive. The most obvious example used is when there is an authentication failure. There is no point\nin giving this provider a 2nd chance to join the pool since it is obviously incorrectly configured.\nAn override feature has been added to the web interface which provides you with option to change a specific configuration limit, active status and MessageException status.\nIf it has failed and you wish to re-activate it - you should remove Message Exception and set active to true.\nThese are dynamic values that are over-written upon application restart.

\n

Configuring sendgrid or other API's/mail plugins to work with queuemail plugin

\n

Please note this is an example tested and working, whilst this covers sendGrid, this theory could be expanded\nover other mail plugin's or mail api's.

\n

Added the plugin to test site:

\n
 compile 'desirableobjects.grails.plugins:grails-sendgrid:2.0.1'\n
\n

Configured application.yml

\n
sendgrid:\n        username: 'myUsername'\n        password: 'bigSecret'\n
\n

A new controller action:

\n
 def testSendGrid() {\n            String myService='myExample'\n            Long userId = queueMailUserService.currentuser\n            def locale = RequestContextUtils.getLocale(request)\n            Email message = new Email(\n                    from: "userA <userA@myDomain.com>",\n                    to: ['userB <userB@gmail.com>'],\n                    subject: 'Subject-------------------------',\n                    text: 'Testing text message being sent via plugin'\n                    //html: params\n            ).save(flush: true)\n            def queue = queueMailApiService.buildEmail(myService, userId, locale, message)\n            flash.message = g.message(code: 'queuemail.reportQueued.label', args: ['TestTextEmail', queue?.id])\n            render  "all done"\n            return\n        }\n
\n

MyExampleMailingService enhances or modifies the behaviour of sendMail function\nthat resides in QueueMailBaseService and is what this service extends from.

\n

My first configured job is 'sendGrid': 2,. If you look within sendMail segment below you will notice\nif (sendAccount=='sendGrid') {.\nWhilst it is within the limitation of 2 jobs it will the if statement and use sendGridService.sendMail.\nFeel free to add other if statements and expand on the idea to other third party\nemail plugin's or custom mail api's.\nThe final else should be left as it is since it will return only when it hits a job that no longer matches your defined if statements.\nSo in this example 'mailConfigExample2' will hit the else block after 2 email's was sent via sendGrid because\nexecutor.getSenderCount would mark sendGrid down and return mailConfigExample2 for the next email's.

\n
\nimport org.grails.plugin.queuemail.EmailQueue\nimport org.grails.plugin.queuemail.QueueMailBaseService\nimport org.grails.plugin.queuemail.enums.MessageExceptions\n\nclass MyExampleMailingService extends QueueMailBaseService {\n\n\tdef sendGridService\n\n\tdef configureMail(executor,EmailQueue queue) {\n\t\tdef jobConfigurations = [\n\t\t\t\t'sendGrid': 2,\n\t\t\t\t'mailConfigExample2': 100,\n\t\t\t]\n\n\t\tsendMail(executor,queue,jobConfigurations,MyExampleMailingService.class)\n\t}\n\t\n\t@Override\n    def sendMail(executor,queue,jobConfigurations,Class clazz,MessageExceptions currentException=null) {\n   \t\tboolean failed=true\n   \t\tboolean resend=false\n   \t\tString sendAccount\n   \t\tString error=''\n   \t\tString code\n   \t\tList args\n   \t\ttry {\n   \t\t\tif (jobConfigurations) {\n   \t\t\t\tsendAccount = executor.getSenderCount(clazz, jobConfigurations, queue.id,currentException)\n   \t\t\t\tif (sendAccount) {\n   \t\t\t\t\tif (sendAccount=='sendGrid') {\n   \t\t\t\t\t\tprintln "Sending via sendGrid"\n   \t\t\t\t\t\ttry {\n   \t\t\t\t\t\t\tsendGridService.sendMail {\n   \t\t\t\t\t\t\t\tfrom "${queue.email.from}"\n   \t\t\t\t\t\t\t\tqueue.email?.to?.each { t ->\n   \t\t\t\t\t\t\t\t\tprintln "sending to ${t}"\n   \t\t\t\t\t\t\t\t\tto "${t}"\n   \t\t\t\t\t\t\t\t}\n   \t\t\t\t\t\t\t\tsubject queue.email.subject+"-- from sendgrid"\n   \t\t\t\t\t\t\t\tbody " from sendGrid"\n   \t\t\t\t\t\t\t}\n   \t\t\t\t\t\t} catch (Exception e) {\n   \t\t\t\t\t\t\tprintln "SendGrid had error E: ${e}"\n   \t\t\t\t\t\t\tfailed=true\n   \t\t\t\t\t\t\tcode='sendgrid.failed'\n   \t\t\t\t\t\t}\n   \t\t\t\t\t} else {\n   \t\t\t\t\t\tprintln "Returning it back to how plugin was doing things"\n   \t\t\t\t\t\tqueueMailService.sendEmail(sendAccount,queue)\n   \t\t\t\t\t\tfailed=false\n   \t\t\t\t\t}\n   \t\t\t\t} else {\n   \t\t\t\t\tcode = 'queuemail.dailyLimit.label'\n   \t\t\t\t\targs = [jobConfigurations]\n   \t\t\t\t}\n   \t\t\t} else {\n   \t\t\t\tcode = 'queuemail.noConfig.label'\n   \t\t\t}\n   \t\t}catch (e) {\n   \t\t\tfailed=true\n   \t\t\tString currentError = e.getClass().simpleName\n   \t\t\tif (MessageExceptions.values().any{it.toString() == currentError}) {\n   \t\t\t\tcurrentException=currentError\n   \t\t\t\tdef errors = MessageExceptions.verifyStatus(currentException)\n   \t\t\t\tif (errors) {\n   \t\t\t\t\tresend=errors.resend\n   \t\t\t\t}\n   \t\t\t}\n   \t\t} finally {\n   \t\t\tif (failed) {\n   \t\t\t\tactionFailed(executor, queue, jobConfigurations, clazz, sendAccount, error, code, args,resend,currentException)\n   \t\t\t}\n   \t\t}\n   \t}\n}\n
\n" }, { "bintrayPackage": { "name": "rabbitmq", "repo": "plugins", "owner": "puneetbehl", "desc": "The RabbitMQ plugin provides integration with the RabbitMQ Messaging System.", "labels": [ "messaging", "rabbitmq" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails-plugins/grails-rabbitmq/issues", "latestVersion": "2.0.0", "updated": "2016-03-31T13:31:54.773Z", "systemIds": [ "org.grails.plugins:rabbitmq" ], "vcsUrl": "https://github.com/grails-plugins/grails-rabbitmq" }, "documentationUrl": "https://grails-plugins.github.io/grails-rabbitmq/", "mavenMetadataUrl": null, "readme": "

\"Build

\n

grails-rabbitmq

\n

Grails RabbitMQ Plugin

\n

Sample Applicatoin

\n" }, { "bintrayPackage": { "name": "rabbitmq-native", "repo": "grails-plugins", "owner": "budjb", "desc": "A messaging plugin for Grails using RabbitMQ.\r\n\r\nThis plugin gives application authors a powerful framework to quickly get a scalable messaging solution running quickly.", "labels": [ "messaging", "rabbitmq" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/budjb/grails-rabbitmq-native/issues", "latestVersion": "4.0.0", "updated": "2019-09-18T14:54:18.779Z", "systemIds": [ "org.grails.plugins:rabbitmq-native" ], "vcsUrl": "https://github.com/budjb/grails-rabbitmq-native" }, "documentationUrl": "https://budjb.github.io/grails-rabbitmq-native/", "mavenMetadataUrl": null, "readme": "
\n

RabbitMQ Native plugin for Grails

\n
\n
\n

Documentation

\n
" }, { "deprecated": "Source repository is archived.", "bintrayPackage": { "name": "recaptcha", "repo": "plugins", "owner": "iamthechad", "desc": "Grails 3 ReCaptcha and MailHide plugin", "labels": [ "mailhide", "captcha" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/iamthechad/grails3-recaptcha/issues", "latestVersion": "3.2.0", "updated": "2018-05-06T00:50:59.682Z", "systemIds": [ "org.grails.plugins:recaptcha" ], "vcsUrl": "https://github.com/iamthechad/grails3-recaptcha.git" }, "documentationUrl": "https://iamthechad.github.io/grails3-recaptcha/", "mavenMetadataUrl": null, "readme": "

\"Download\"\n\"Build\n\"Coverage\n\"Known\n\"License\"\n\"Maintenance\"\n\"Badges\"

\n\n\n

Table of Contents generated with DocToc

\n\n\n

Introduction

\n

This plugin is designed to make using the ReCaptcha service within Grails 3 easy. In order to use this plugin, you must have a ReCaptcha account, available from http://www.google.com/recaptcha.

\n

Installation

\n

Add the following to your build.gradle

\n
compile "org.grails.plugins:recaptcha:3.2.0"\n
\n

Configuration

\n

Add the following to your application's application.yml file:

\n
recaptcha:\n    publicKey: "your public key"\n    privateKey: "your private key"\n    includeScript: true\n    includeNoScript: true\n
\n

These configurations can also be placed at environment-specific locations in the configuration:

\n
environments:\n    development:\n        recaptcha:\n            enabled: false\n    production:\n        recaptcha:\n            enabled: true\n
\n

Externalized Configuration

\n

See the Grails docs for examples of using externalized configuration files. The ReCaptcha config can be externalized as\nthe .groovy file (easiest), or it can be converted into a Java .properties file.

\n

Usage - ReCaptcha

\n

The plugin is simple to use. In order to use it, there are four basic steps:

\n

Edit the Configuration

\n

The configuration values are pretty self-explanatory, and match with values used by the ReCaptcha service. You must enter your public and private ReCaptcha keys, or errors will be thrown when trying to display a captcha.

\n

Proxy Server Configuration

\n

If your server needs to connect through a proxy to the ReCaptcha service, add the following to the ReCaptcha configuration.

\n
recaptcha:\n\tproxy:\n    \tserver: ""   // IP or hostname of proxy server\n    \tport: ""     // Proxy server port, defaults to 80\n    \tusername: "" // Optional username if proxy requires authentication\n    \tpassword: "" // Optional password if proxy requires authentication\n
\n

Only the server property is required. The port will default to 80 if not specified. The username and password properties need to be specified only when the proxy requires authentication.

\n

Like other configurations, this can be placed at the top-level recaptcha entry, or it can be specified on a per-environment basis.

\n

Timeout Configuration

\n

If there are issues connecting to Google for verifying the captcha, some of the network timeouts can be changed.

\n
recaptcha:\n    timeoutConfig:\n        connectTimeout: 10000 // Timeout for making the network connection in millis. Defaults to 10000\n        readTimeout: 1000     // Timeout for waiting on the network response in millis. Defaults to 1000\n
\n

connectTimeout and readTimeout can be specified together or independently of each other.

\n

Like other configurations, this can be placed at the top-level recaptcha entry, or it can be specified on a per-environment basis.

\n

Use the Tag Library

\n

<recaptcha:ifEnabled>

\n

This tag is a simple utility that will render its contents if the captcha is enabled in the configuration.

\n

<recaptcha:ifDisabled>

\n

This tag is a simple utility that will render its contents if the captcha is disabled in the configuration.

\n

<recaptcha:recaptcha>

\n

This tag is responsible for generating the correct HTML output to display the captcha. It supports the following attributes:

\n\n

See the ReCaptcha Client Guide for more details.

\n

<recaptcha:script>

\n

This tag will render the required <script> tag. Combine this with the global or tag-level includeScript=false setting to allow putting the <script> tag elsewhere in your markup. This tag also supports the "lang" attribute. This does not work in the <head> section of the page

\n

<recaptcha:recaptchaExplicit>

\n

This tag is responsible for generating the correct HTML output to support explicit display and usage of the captcha. It supports the following attributes:

\n\n

For more information about explicit mode captchas, see the ReCaptcha documentation.

\n

<recaptcha:renderParameters>

\n

This utility tag will generate the JSON string used as a parameter to the grecaptcha.render() function. It supports the following attributes:

\n\n

See the ReCaptcha Client Guide for more details.

\n

<recaptcha:ifFailed>

\n

This tag will render its contents if the previous validation failed.

\n

Verify the Captcha

\n

In your controller, call recaptchaService.verifyAnswer(session, request.getRemoteAddr(), params) to verify the answer provided by the user. This method will return true or false. Also note that verifyAnswer will return true if the plugin has been disabled in the configuration - this means you won't have to change your controller.

\n

Examples

\n

Here's a simple example pulled from an account creation application.

\n

Tag Usage for Automatic Rendering

\n

This is the most common usage scenario.

\n

In our GSP, we add the code to show the captcha:

\n
<recaptcha:ifEnabled>\n    <recaptcha:recaptcha theme="dark"/>\n</recaptcha:ifEnabled>\n
\n

In this example, we're using ReCaptcha's dark theme. Leaving out the theme attribute will default the captcha to the light theme.

\n

Tag Usage for Explicit Rendering

\n

In our GSP, we add code like the following:

\n
<script type="text/javascript">\n  var onloadCallback = function() {\n    grecaptcha.render('html_element', <recaptcha:renderParameters theme="dark" type="audio" tabindex="2"/>);\n  };\n</script>\n<g:form action="myAction" method="post">\n  <recaptcha:ifEnabled>\n    <recaptcha:recaptchaExplicit loadCallback="onloadCallback"/>\n    <div id="html_element"></div>\n  </recaptcha:ifEnabled>\n  <br/>\n  <g:submitButton name="submit"/>\n</g:form>\n
\n

In this example, we're using ReCaptcha's dark theme, with an audio captcha and a tabindex of 2.

\n

For more information about explicit mode captchas, see the ReCaptcha documentation.

\n

Tag Usage with Separate Script

\n

Set the includeScript value to false either at the tag level (below), or in the global ReCaptcha settings.

\n
<body>\n  <g:form action="validateNormal" method="post" >\n    <recaptcha:ifEnabled>\n      <recaptcha:recaptcha includeScript="false"/>\n    </recaptcha:ifEnabled>\n    <br/>\n    <g:submitButton name="submit"/>\n  </g:form>\n  <recaptcha:script/>\n</body>\n
\n

This will cause the <script src="https://www.google.com/recaptcha/api.js?" async="" defer=""></script> tag to be output separately at the bottom of the document instead of just before the <div> containing the captcha.

\n

Customizing the Language

\n

If you want to change the language your captcha uses, set lang = "someLang" in the <recaptcha:recaptcha> or <recaptcha:recaptchaExplcit> tags.

\n

See ReCaptcha Language Codes for available languages.

\n

Verify User Input

\n

Here's an abbreviated controller class that verifies the captcha value when a new user is saved:

\n
import com.megatome.grails.RecaptchaService\nclass UserController {\n\tRecaptchaService recaptchaService\n\n\tdef save = {\n\t\tdef user = new User(params)\n\t\t...other validation...\n\t\tdef recaptchaOK = true\n\t\tif (!recaptchaService.verifyAnswer(session, request.getRemoteAddr(), params)) {\n\t\t\trecaptchaOK = false\n\t\t}\n\t\tif(!user.hasErrors() && recaptchaOK && user.save()) {\n\t\t\trecaptchaService.cleanUp(session)\n\t\t\t...other account creation acivities...\n\t\t\trender(view:'showConfirmation',model:[user:user])\n\t\t}\n\t\telse {\n\t\t\trender(view:'create',model:[user:user])\n\t\t}\n\t}\n}\n
\n

Testing

\n

You can look at the test cases in the plugin itself, or you can implement something similar to:

\n
private void buildAndCheckAnswer(String postText, boolean expectedValid) {\n    def stub = new StubFor(Post.class)\n    stub.demand.hasProperty(3..3) { true }\n    stub.demand.setUrl() {}\n    stub.demand.setProxy() {}\n    stub.demand.getQueryParams(3..3) { new QueryParams(null) }\n    stub.demand.getResponse() { postText == null ? null : new JsonSlurper().parseText(postText) }\n\n    stub.use {\n        def response = r.checkAnswer("123.123.123.123", "response")\n\n        assert response == expectedValid\n    }\n}\n
\n

The postText parameter represents the response from the ReCaptcha server. Here are examples of simulating success and failure results:

\n
when:"A successful response message"\ndef answer = """{ "success": true }"""\n\nthen:\nbuildAndCheckAnswer(answer, true)\n\nwhen:"A failure response message"\nanswer = """{ "success": false }"""\n\nthen:\nbuildAndCheckAnswer(answer, false)\n
\n

Contributing

\n

See the contribution guidelines.

\n

Suggestions or Comments

\n

Feel free to submit questions through GitHub or to StackOverflow.

\n

Alternatively you can contact me directly - cjohnston at megatome dot com

\n" }, { "bintrayPackage": { "name": "recaptcha-spring-security", "repo": "grails-plugins", "owner": "snimavat", "desc": "Recaptcha support for Spring security", "labels": [ "security", "spring-security", "captcha" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/snimavat/recaptcha-spring-security/issues", "latestVersion": "3.0.1", "updated": "2017-03-02T10:11:50.103Z", "systemIds": [ "org.grails.plugins:recaptcha-spring-security" ], "vcsUrl": "https://github.com/snimavat/recaptcha-spring-security" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

recaptcha-spring-security

\n

Grails: Using recaptcha with spring security core for brute force defender

\n

based in: Brute Force Defender

\n

Requirements

\n
    \n
  1. Grails 2.3.2+
  2. \n
  3. Spring Security Core Plugin (2.0-RC3+)
  4. \n
  5. ReCaptcha Plugin (0.6.9+)
  6. \n
\n

Installation

\n
    \n
  1. \n

    clone the repository: git clone https://github.com/rpalcolea/recaptcha-spring-security.git

    \n
  2. \n
  3. \n

    Enter to the repository via command line.

    \n
  4. \n
  5. \n

    package the plugin: grails package-plugin

    \n
  6. \n
\n

Configuration

\n

Config.groovy

\n

Configure recaptcha plugin

\n

And then Add the following lines to your Grails Config.groovy file:

\n
bruteforcedefender {\n\ttime = 5\n\tallowedNumberOfAttempts = 3\n}\n
\n

time = minutes mantaining failed attempts allowed\nNumberOfAttempts = number of failed attempts before showing the recaptcha widget.

\n

Adding the recaptcha to your auth view

\n

Open your auth.gsp (/grails-app/views/login/auth.gsp) and add the next line wherever you want to render the recaptcha after the attempts.

\n
      <g:recaptchaLogin/>\n
\n

Note: The plugin depends on spring security authentication events and so it sets grails.plugin.springsecurity.useSecurityEventListener = true

\n

Extras

\n

Thanks to Vinco Orbis and Burt Beckwith

\n

Thanks to JetBrains for Awesome IntelliJ Idea

\n\n" }, { "bintrayPackage": { "name": "grails-redis", "repo": "grails", "owner": "grails", "desc": "Grails Redis plugin", "labels": [ "redis" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails/grails-redis/issues", "latestVersion": "4.0.1", "updated": "2023-12-20T15:58:07.000Z", "systemIds": [ "org.grails.plugins:grails-redis" ], "vcsUrl": "https://github.com/grails/grails-redis" }, "documentationUrl": null, "mavenMetadataUrl": "https://repo1.maven.org/maven2/org/grails/plugins/grails-redis/maven-metadata.xml", "readme": "

\"Build

\n

Grails 3

\n

The 2.X version of the plugin is compatible only with grails 3.

\n

Grails Redis Plugin

\n

For integration between Redis and Grails GORM layer, see the Redis GORM plugin.

\n

That plugin was originally called "redis" (the name of this plugin), but it has since been refactored to "redis-gorm" and now relies on this plugin for connectivity.

\n

What is Redis?

\n

The best definition of Redis that I've heard is that it is a "collection of data structures exposed over the network".

\n

Redis is an insanely fast key/value store, in some ways similar to memcached, but the values it stores aren't just dumb blobs of data. Redis values are data structures like strings, lists, hash maps, sets, and sorted sets. Redis also can act as a lightweight pub/sub or message queueing system.

\n

Redis is used in production today by a number of very popular websites including Craigslist, StackOverflow, GitHub, The Guardian, and Digg.

\n

It's commonly lumped in with other NoSQL technologies and is commonly used as a caching layer. It has some similarities to Memcached or Tokyo Tyrant. Because Redis provides network-available data structures, it's very flexible and it's able to solve all kinds of problems. The creator of Redis, Salvatore Sanfilippo, has a nice post on his blog showing how to take advantage of Redis by just adding it to your stack. With the Grails Redis plugin, adding Redis to your grails app is very easy.

\n

I've created an introduction to Redis using groovy that shows you how to install redis and use some basic groovy commands. There is also a presentation that I gave at gr8conf 2011.

\n

The official Redis documentation is fantastic and includes a comprensive list of Redis commands, each command web page also has an embedded REPL that lets you test out the command against a live Redis server.

\n

What is Jedis?

\n

Jedis is the Java Redis connection library that the Grails Redis plugin uses. It's actively maintained, very fast, and doesn't try to do anything too clever. One of the nice things about it is that it doesn't try to munge around with the Redis command names, but follows them as closely as possible. This means that for almost all commands, the Redis command documentation can also be used to understand how to use the Jedis connection objects. You don't need to worry about translating the Redis documentation into Jedis commands.

\n

Installation

\n
grails install-plugin redis\n
\n

Out of the box, the plugin expects that Redis is running on localhost:6379. You can modify this (as well as any other pool config options) by adding a stanza like this to your grails-app/conf/Config.groovy file:

\n
grails {\n    redis {\n        poolConfig {\n            // jedis pool specific tweaks here, see jedis docs & src\n            // ex: testWhileIdle = true\n        }\n        timeout = 2000 //default in milliseconds\n        password = "somepassword" //defaults to no password\n    useSSL = false //or true to use SSL\n\n        // requires either host & port combo, or a sentinels and masterName combo\n\n        // use a single redis server (use only if nore using sentinel cluster)\n        port = 6379\n        host = "localhost"\n        database = 5 // set default database to 5\n\n        // use redis-sentinel cluster as opposed to a single redis server (use only if not use host/port)\n        sentinels = [ "host1:6379", "host2:6379", "host3:6379" ] // list of sentinel instance host/ports\n        masterName = "mymaster" // the name of a master the sentinel cluster is configured to monitor\n    }\n\n}\n
\n

The poolConfig section will let you tweak any of the setter values made available by the JedisPoolConfig. It implements the Apache Commons GenericObjectPool.

\n

NOTE: Please see Redis Sentinel - Documentation for more info on using redis-sentinel for high availability

\n

Plugin Usage

\n

RedisService Bean

\n
def redisService\n
\n

The redisService bean wraps the pool connection. It has a number of caching/memoization helper functions, template methods, and basic Redis commands, it will be your primary interface to Redis.

\n

The service overrides propertyMissing and methodMissing to delegate any missing requests to a Redis connection object. This means that any method that you'd normally call on a Redis connection object can be called directly on redisService.

\n
// overrides propertyMissing and methodMissing to delegate to redis\ndef redisService\n\nredisService.foo = "bar"\nassert "bar" == redisService.foo\n\nredisService.sadd("months", "february")\nassert true == redisService.sismember("months", "february")\n
\n

It also provides a template method called withRedis that takes a closure as a parameter. It passes a Jedis connection object to Redis into the closure. The template method automatically gets an object out of the pool and ensures that it gets returned to the pool after the closure finishes (even if there's an error).

\n
redisService.withRedis { Jedis redis ->\n    redis.set("foo", "bar")\n}\n
\n

The advantage to calling withRedis rather than just calling methods directly on redisService is that multiple commands will only use a single connection instance, rather than one per command.

\n

Redis also allows you to pipeline commands. Pipelining allows you to quickly send commands to Redis without waiting for a response. When the pipeline is executed, it returns a Result object, which works like a Future to give you the results of the pipeline. See the Jedis documentation on pipelining for more details. It works pretty much like the withRedis template does:

\n
redisService.withPipeline { Pipeline pipeline ->\n    pipeline.set("foo", "bar")\n}\n
\n

Redis has the notion of transactions, but it's not exactly the same as a database transaction. Redis transactions guarantee that all of the commands in the transaction will be executed as an atomic unit. Because Redis is single threaded, you're guaranteed to execute atomically and have a known state throughout the transaction. Redis does not support rolling back modifications that happen during a transaction.

\n

The withTransaction template method automatically opens and closes the transaction for you. If the closure doesn't throw and exception, it will tell Redis to execute the transaction

\n
redisService.withTransaction { Transaction transaction ->\n    transaction.set("foo", "bar")\n}\n
\n

Memoization

\n

Memoization is a write-through caching technique. The plugin gives a number of methods that take a key name, and a closure as parameters. These methods first check Redis to see if the key exists. If it does, it returns the value of the key and does not execute the closure. If it does not exist in Redis, it executes the closure and saves the result in Redis under the key. Subsequent calls will then be served the cached value from Redis rather than recalculating.

\n

This technique is very useful for caching values that are frequently requested but expensive to calculate.

\n

As of version 1.2 you may also use the new memoize annotations. See the Memoization Annotation section for usage and examples.

\n

There are methods for the basic Redis data types:

\n

String Memoization

\n
redisService.memoize("user:$userId:helloMessage") {\n    // expensive to calculate method that returns a String\n    "Hello ${security.currentLoggedInUser().firstName}"\n}\n
\n

By default, the key/value will be cached forever in Redis, you can ensure that the key is refreshed either by deleting the key from Redis, making the key include a date or timestamp, or by using the optional expire parameter, the value is the number of seconds before Redis should expire the key:

\n
def ONE_HOUR = 3600\nredisService.memoize("user:$userId:helloMessage", [expire: ONE_HOUR]) {\n    """\n    Hello ${security.currentLoggedInUser().firstName.\n    The temperature this hour is ${currentTemperature()}\n    """\n}\n
\n

Domain Object Memoization

\n

You can memoize a single domain object with redis. It will cache the ID of the domain object returned from the closure and on subsequent cache hits will return a proxy domain object using grails DomainObject.load(cachedId).

\n
String key = "user:42:favorite:author"\nAuthor author = redisService.memoizeDomainObject(Author, key) {\n    Author author = ... // expensive method to calculate user 42's favorite author...\n    return author\n}\n
\n

Now that you have the proxy object for the Author, you can do queries with it without actually having to hydrate the object (and anything it eagerly loads):

\n
def recommendedBooks = Book.findByAuthor(author)\n
\n

The object has the id field populated, but the remaining fields are lazily loaded only if their values are requested, so you can still do:

\n
println author.name\n
\n

To actually print out the name of the author.

\n

Domain List Memoization

\n

You can also memoize a list of domain object identifiers. It doesn't cache the entire domain object, just the database IDs of the domain objects in a returned list.

\n

This allows you to still grab the freshest objects from the database, but not repeatedly create an expensive list. This could be a big database query that joins a bunch of tables. Or some other process that does additional filtering based on selections the user has made in the UI. Something ephemeral for that session or user, that you don't want to persist, but need to be able to react to.

\n
def key = "user:$id:friends-books-user-does-not-own"\n\nredisService.memoizeDomainList(Book, key, ONE_HOUR) { redis ->\n    // expensive process to calculate all friend\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffds books and filter out books\n    // that the user already owns, this stores the list of determined Book IDs\n    // in Redis, but hydrates the Book objects from the DB\n}\n
\n

Other Memoization Methods

\n

There are other memoization methods that the plugin provides, check out the RedisService.groovy and the plugin tests for the exhaustive list.

\n
// Redis Hash memoize methods\n\nredisService.memoizeHash("saved-hash") { return [foo: "bar"] }\n\nredisService.memoizeHashField("saved-hash", "foo") { return "bar" }\n\n// Redis List memoize method\nredisService.memoizeList("saved-list") { return ["foo", "bar", "baz"] }\n\n// Redis Set memoize method\nredisService.memoizeSet("saved-set") { return ["foo", "bar", "baz"] as Set }\n\n// Redis Sorted Set memoize method\nredisService.memoizeScore("saved-sorted-set", "set-item") { return score }\n
\n

Other Methods

\n

The plugin also provides a few utility methods such as:

\n
redisService.flushDB() // dangerous!!!! should probably only be used for test cleanup\n\n// deletes all keys in the database matching a pattern, this is fairly expensive\n// as it uses the <code>keys</code> operation.  If you're doing this a lot and\n// have many keys in redis, you should be aggregating your own set of keys that\n// you'll later want to delete\nredisService.deleteKeysWithPattern("key:pattern:*")\n
\n

Redis Pool Bean

\n

You can have direct access to the pool of Redis connection objects by injecting redisPool into your code. Normally, you won't want to directly work with the pool, and instead interact with the redisService bean, but you have the option to manually work with the pool if desired.

\n
def redisPool\n
\n

Redis Taglib

\n

The redis:memoize TagLib lets you leverage memoization within your GSP files. Wrap it around any expensive to generate text and it will cache it and quickly serve it from Redis.

\n
<redis:memoize key="mykey" expire="3600">\n    <!--\n        insert expensive to generate GSP content here\n\n        taglib body will be executed once, subsequent calls\n        will pull from redis till the key expires\n    -->\n    <div id='header'>\n        ... expensive header stuff here that can be cached ...\n    </div>\n</redis:memoize>\n
\n

Multiple Redis Servers

\n

If you are using multiple redis servers in your environment which are NOT clustered and would like to perform discrete operations on them seperately from a single application, you can accomplish that by by adding some configuration to your application.

\n

The configuration block for redis accepts the following connections block parameters.

\n

Config.groovy

\n
grails {\n    redis {\n        poolConfig {\n            // pool specific tweaks here\n            // for parms see https://github.com/xetorthio/jedis/blob/master/src/main/java/redis/clients/jedis/JedisPoolConfig.java\n            // numTestsPerEvictionRun = 4\n        }\n\n        // requires either host & port combo, or a sentinels and masterName combo\n\n        // use a single redis server (use only if nore using sentinel cluster)\n        port = 6379\n        host = "localhost"\n\n        // use redis-sentinel cluster as opposed to a single redis server (use only if not use host/port)\n        sentinels = [ "host1:6379", "host2:6379", "host3:6379" ] // list of sentinel instance host/ports\n        masterName = "mymaster" // the name of a master the sentinel cluster is configured to monitor\n\n        connections {\n            cache {\n                poolConfig {\n                    // pool specific tweaks here\n                    // for parms see https://github.com/xetorthio/jedis/blob/master/src/main/java/redis/clients/jedis/JedisPoolConfig.java\n                    // numTestsPerEvictionRun = 4\n                }\n\n                // requires either host & port combo, or a sentinels and masterName combo\n\n                // use a single redis server (use only if nore using sentinel cluster)\n                port = 6380\n                host = "localhost"\n\n                // use redis-sentinel cluster as opposed to a single redis server (use only if not use host/port)\n                sentinels = [ "host1:6380", "host2:6380", "host3:6380" ] // list of sentinel instance host/ports\n                masterName = "cache" // the name of a master the sentinel cluster is configured to monitor\n            }\n            search {\n                poolConfig {\n                    // pool specific tweaks here\n                    // for parms see https://github.com/xetorthio/jedis/blob/master/src/main/java/redis/clients/jedis/JedisPoolConfig.java\n                    // numTestsPerEvictionRun = 4\n                }\n\n                // requires either host & port combo, or a sentinels and masterName combo\n\n                // use a single redis server (use only if nore using sentinel cluster)\n                port = 6381\n                host = "localhost"\n\n                // use redis-sentinel cluster as opposed to a single redis server (use only if not use host/port)\n                sentinels = [ "host1:6381", "host2:6381", "host3:6381" ] // list of sentinel instance host/ports\n                masterName = "search" // the name of a master the sentinel cluster is configured to monitor\n            }\n        }\n    }\n}\n
\n

The standard config block for the default connection has not changed. The new configuration is under the connections block. You will need to name your connections ('cache' and 'search' in the above block). The names must be unique.

\n

A new service bean will be wired in addition to the default redisService bean with the capitalized connection name appended to it. For example the above two connections would create a redisServiceCache and redisServiceSearch bean you can reference from your application code. If desired, you can also access the connection-specific redisPool beans that are created using the same naming convention, in this example they would be redisPoolCache and redisPoolSearch.

\n

In addition to the newly wired beans, you may also choose to continue using the standard redisService bean and simply refer to the connections by name when invoking targets on the service via redisService.withConnection('cache').withRedis{...} or redisService.withConnection('search').memoize(key){...}.

\n

Note: It is up to you if you prefer using the main redisService bean and the withConnection method or if you want to inject the additional service beans. The end result is the same and the withConnection is simply a pass through to the newly created beans.

\n
class FooService {\n\n    def redisService\n    // custom created beans for each connection, you can use these or just use the `withConnection` method\n    // both methods are demonstrated below for example purposes, but you'd like choose one method or the other\n    def redisServiceCache\n    def redisServiceSearch\n\n    def doWork(){\n        redisService.withRedis { Jedis redis ->\n            redis.set("foo", "bar")\n        }\n\n        redisService.withConnection('cache').withTransaction { Jedis redis ->\n            redis.set("foo", "bar")\n        }\n\n        redisServiceSearch.withPipeline { Jedis redis ->\n            redis.set("foo", "bar")\n        }\n\n        redisServiceCache.memoize("somecachekey") {Jedis redis ->\n            return cacheData\n        }\n\n        redisService.withConnection('search').memoizeDomainList(Book, "domainkey"){\n            return Book.findAllByTitleInList(["book1", "book3"])\n        }\n\n        redisService.memoizeDomainIdList(Book, "domainkey"){\n            return Book.findAllByTitleInList(["book1", "book3"])\n        }\n\n        redisServiceCache.memoizeDomainObject(Book, "domainkey"){\n            return Book.get(book1.id)\n        }\n\n        redisServiceSearch.memoizeHash("domainkey"){\n             return [foo: "bar"]\n        }\n    }\n}\n
\n

Memoization Annotations

\n

Memoization Annotations

\n

These currently do not work with grails 3.0+ and domain classes. Please only used these on service classes for grails 3.0+ until we can fix this

\n

In addition to using the concrete and finite redisService.memoize* methods, as of version 1.2 you may now also annotate a method with an appropriate @Memoize* annotation. This will perform an AST transformation at compile time and wrap the entire body of the method with the corresponding memoization method. The parameters such as key and expire are passed into the annotation and used in the redisService memoize method calls.

\n

The following are available as annotations:

\n\n \n \n \n \n \n \n \n \n \n \n
AnnotationDescription
@MemoizeUsed to memoize methods that return a \"string\" - redisService.memoize
@MemoizeObjectUsed to memoize methods that return an object - redisService.memoize
@MemoizeDomainObjectUsed to memoize methods that return a domain object - redisService.memoizeDomain
@MemoizeDomainListUsed to memoize methods that return a domain object list - redisService.memoizeDomainList
@MemoizeHashUsed to memoize methods that return a hash - redisService.memoizeHash
@MemoizeHashFieldUsed to memoize methods that return a hash field - redisService.memoizeHashField
@MemoizeListUsed to memoize methods that return a list - redisService.memoizeList
@MemoizeSetUsed to memoize methods that return a set - redisService.memoizeSet
@MemoizeScoreUsed to memoize methods that returns a score from a hash - redisService.memoizeScore
\n

There are integration usage tests written in spock for services at RedisMemoizeServiceSpec.groovy and for domains at RedisMemoizeDomainSpec.groovy

\n

Memoization Annotation Keys

\n

Since the value of the key must be passed in but will also be transformed by AST, we can not use the $ style gstring values in the keys. Instead you will use the # sign to represent a gstring value such as @Memoize(key = "#{book.title}:#{book.id}").

\n

During the AST tranformation these will be replaced with the $ character and will evaluate correctly during runtime as redisService.memoize("${book.title}:${book.id}"){...}.

\n

Anything that is not in the format key='#text' or key="${text}" will be treated as a string literal. Meaning that key="text" would be the same as using the literal string "text" as the memoize key redisService.memoize("text"){...} instead of the variable $text.

\n

Any variable that you use in the key property of the annotation will need to be in scope for this to work correctly. You will only get a RUNTIME error if you use a variable reference that is out of scope.

\n

This also applies to the expire field.

\n

Memoization Annotation Notes

\n

You are not required to import the import grails.plugin.redis.RedisService namespace or declare the service def redisService on any objects you wish to use this annotation with as the AST transform will detect whether this field is on your object and add it for you. You may certainly have either the import or def statements if you would like, but they are not required if you use the @Memoize* annotations.

\n

The user should be aware that any annotated method will be completely wrapped in the redis service call so any calculations that are contained within will also be wrapped and not executed of the key is in scope and not expired.

\n

If the compile succeeds but runtime fails or throws an exception, make sure the following are valid:\n* Your key OR value is configured correctly.\n* The key uses a #{} for all variables you want referenced.

\n

If the compile does NOT succeed make sure check the stack trace as some validation is done on the AST transform for each annotation type:\n* Required annotation properties are provided.\n* When using expire it is a valid Integer type variable.\n* When using value it is a valid closure.\n* When using key it is a valid String.

\n

@Memoize

\n

The @Memoize annotation is to be used when dealing with objects that are stored in Redis as strings. This annotation takes the following parameters:

\n
value   - A closure in the following format. (key OR value required)\nkey     - A unique key for the data cache. (key OR value required)\nexpire  - Expire time in seconds.  Will default to never so only pass a value like 3600 if you want value to expire.\n
\n

You can either specify a closure OR a key and expire. When using the closure style key @Memoize({"#{text}"}) you may not pass a key or expire to the annotation as the closure will be evaluated directly and used as the key value. This is due to a limitation on how Java deals with closure annotation parameters.

\n

Here is an example of usage:

\n
@Memoize({"#{text}"})\ndef getAnnotatedTextUsingClosure(String text, Date date) {\n    println 'cache miss getAnnotatedTextUsingClosure'\n    return "$text $date"\n}\n\n@Memoize(key = '#{text}')\ndef getAnnotatedTextUsingKey(String text, Date date) {\n    println 'cache miss getAnnotatedTextUsingKey'\n    return "$text $date"\n}\n\n//expire this extremely fast\n@Memoize(key = '#{text}', expire = '1')\ndef getAnnotatedTextUsingKeyAndExpire(String text, Date date) {\n    println 'cache miss getAnnotatedTextUsingKeyAndExpire'\n    return "$text $date"\n}\n\n//configurable expire time to live\n@Memoize(key = '#{text}', expire = '#{grailsApplication.config.cache.ttl}')\ndef getAnnotatedTextUsingKeyAndExpire(String text, Date date) {\n    println 'cache miss getAnnotatedTextUsingKeyAndExpire'\n    return "$text $date"\n}\n\n@Memoize(key = "#{book.title}:#{book.id}")\ndef getAnnotatedBook(Book book) {\n    println 'cache miss getAnnotatedBook'\n    return book.toString()\n}\n
\n

@MemoizeObject

\n

The @MemoizeObject annotation is to be used when dealing with simple (non-domain) objects that are to have their contents stored in Redis in JSON form. The simple object being returned by the return statement will be converted to JSON, stored in Redis, then converted from JSON back to the object. It is important to ensure that the object class you're using is able to be converted to and from JSON for this annotation to work. This annotation takes the following parameters:

\n
key     - A unique key for the data cache. (required)\nexpire  - Expire time in seconds.  Will default to never so only pass a value like 3600 if you want value to expire.\nclazz   - The class of the object to be memoizing. (required)\n
\n

Here is an example of usage:

\n
@MemoizeObject(key = "#{title}", expire = "#{grailsApplication.config.cache.ttl}", clazz = Book.class)\ndef createObject(String title, Date date) {\n    println 'cache miss createObject'\n    new Book(title: title, createDate: date)\n}\n
\n

This method is also available from the RedisService:

\n
redisService.memoizeObject(Book.class, title, grailsApplication.config.cache.ttl) {\n  println 'cache miss createObject'\n  new Book(title: title, createDate: date)\n}\n
\n

@MemoizeDomainObject

\n

The @MemoizeDomainObject annotation is to be used when dealing with domain objects that are to have their id's stored in Redis. See the documentation on Domain Object Memoization above for more details. This annotation takes the following parameters:

\n
key     - A unique key for the data cache. (required)\nexpire  - Expire time in seconds.  Will default to never so only pass a value like 3600 if you want value to expire.\nclazz   - The class of the object to be memoizing. (required)\n
\n

Here is an example of usage:

\n
@MemoizeDomainObject(key = "#{title}", clazz = Book.class)\ndef createDomainObject(String title, Date date) {\n    println 'cache miss createDomainObject'\n    Book.build(title: title, createDate: date)\n}\n
\n

@MemoizeDomainList

\n

The @MemoizeDomainList annotation is to be used when dealing with lists of domain objects that are to have their id's stored in Redis. See the documentation on Domain List Memoization above for more details. This annotation takes the following parameters:

\n
key     - A unique key for the data cache. (required)\nexpire  - Expire time in seconds.  Will default to never so only pass a value like 3600 if you want value to expire.\nclazz   - The class of the object to be memizing. (required)\n
\n

Here is an example of usage:

\n
@MemoizeDomainList(key = "getDomainListWithKeyClass:#{title}", clazz = Book.class)\ndef getDomainListWithKeyClass(String title, Date date) {\n    println 'cache miss getDomainListWithKeyClass'\n    Book.findAllByTitle(title)\n}\n
\n

@MemoizeList

\n

The @MemoizeList annotation is to be used when dealing with list type objects. This annotation takes the following parameters:

\n
value   - A closure in the following format. (key OR value required)\nkey     - A unique key for the data cache. (key OR value required)\nexpire  - Expire time in seconds.  Will default to never so only pass a value like 3600 if you want value to expire.\n
\n

You can either specify a closure OR a key and expire. When using the closure style key @Memoize({"#{text}"}) you may not pass a key or expire to the annotation as the closure will be evaluated directly and used as the key value. This is due to a limitation on how Java deals with closure annotation parameters.

\n

Here is an example of usage:

\n
@MemoizeList(key = "#{list[0]}")\ndef getAnnotatedList(List list) {\n    println 'cache miss getAnnotatedList'\n    return list\n}\n
\n

@MemoizeScore

\n

The @MemoizeScore annotation is to be used when dealing with scores in hashes. This annotation takes the following parameters:

\n
key     - A unique key for the data cache. (required)\nexpire  - Expire time in seconds.  Will default to never so only pass a value like 3600 if you want value to expire.\nmember  - The hash property to store. (required)\n
\n

Here is an example of usage:

\n
@MemoizeScore(key = "#{map.key}", member="foo")\ndef getAnnotatedScore(Map map) {\n    println 'cache miss getAnnotatedScore'\n    return map.foo\n}\n
\n

@MemoizeHash

\n

The @MemoizeHash annotation is to be used when dealing with maps/hash type objects. This annotation takes the following parameters:

\n
value   - A closure in the following format. (key OR value required)\nkey     - A unique key for the data cache. (key OR value required)\nexpire  - Expire time in seconds.  Will default to never so only pass a value like 3600 (one hour) if you want value to expire.\n
\n

You can either specify a closure OR a key and expire. When using the closure style key @Memoize({"#{text}"}) you may not pass a key or expire to the annotation as the closure will be evaluated directly and used as the key value. This is due to a limitation on how Java deals with closure annotation parameters.

\n

Here is an example of usage:

\n
@MemoizeHash(key = "#{map.foo}")\ndef getAnnotatedHash(Map map) {\n    println 'cache miss getAnnotatedHash'\n    return map\n}\n
\n

Grails 3.0

\n

Most things remain the same except configuration in the application.yml file will be done not in dsl closure but YAML style.

\n
---\ngrails:\n  redis:\n    poolConfig:\n      maxIdle: 10\n      doesnotexist: true\n
\n

The package namespace has changed to grails.plugins.redis. Note the addition of the s in plugin[s].

\n

@Memoize annotations currently do NOT work with domain objects and classes. We are working to fix this.

\n

Previously the @Memoize annotations would inject the redisService into your classes, due to changes in how beans are wired in grails 3.0.0+ it is recommended that you\ndefine the service in your classes like the following:

\n
class MyService {\n    \n    RedisService redisService\n    \n    @Memoize()\n    def doFoo(){\n        ...\n    }\n    \n}\n
\n

Release Notes Grails 3.x

\n\n

Release Notes Grails 2.x

\n\n" }, { "bintrayPackage": { "name": "redis-gorm", "repo": "plugins", "owner": "grails", "desc": "GORM - Grails Data Access Framework", "labels": [ "gorm", "nosql", "redis" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails/gorm-redis/issues", "latestVersion": "6.0.4", "updated": "2016-11-07T00:17:00.000Z", "systemIds": [ "org.grails.plugins:redis-gorm" ], "vcsUrl": "https://github.com/grails/gorm-redis" }, "documentationUrl": "https://gorm.grails.org/latest/redis/manual/", "mavenMetadataUrl": null, "readme": "

GORM for Redis

\n

This project implements GORM for the Redis Key/Value Database.

\n

For more information see the following links:

\n\n

For the current development version see the following links:

\n\n" }, { "bintrayPackage": { "name": "remora", "repo": "plugins", "owner": "neilab", "desc": "Remora is a Grails Image / File Upload Plugin formally based on Selfie plugin. Use Remora to attach files to your domain models, upload to a CDN, validate content, produce thumbnails.", "labels": [ "image", "file", "upload" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/neilabdev/remora/issues", "latestVersion": "1.0.1", "updated": "2016-09-15T14:13:10.459Z", "systemIds": [ "com.neilab.plugins.remora:remora" ], "vcsUrl": "https://github.com/neilabdev/remora" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Remora

\n

Remora is a Grails Image / File Upload / Attachment Plugin. It was initially based on the excellent Selfie plugin by bertramlabs, which at the time was limited to grails 2 and implemented using grails column embedding feature to incorporate attachments into the domain model, which was not ideal for my specific project and thus a fork was created to resolve these issues with additional features.

\n

You may use Remora to attach files to your domain models, upload to a CDN, validate content, and produce thumbnails.

\n\n

Installation

\n

Add The Following to your build.gradle:

\n
dependencies {\n    compile ':remora:1.0.1'\n}\n
\n

Configuration

\n

Remora utilizes karman for dealing with asset storage. Karman is a standardized interface for sending files up to CDN's as well as local file stores. It is also capable of serving local files.\nIn order to upload files, we must first designate a storage provider for these files. This can be done in the remora static map in each GORM domain with which you have an Attachment,\nor this can be defined in your application.groovy or 'application.yml'.

\n
\nimport com.neilab.plugins.remora.Attachment\nimport com.neilab.plugins.remora.AttachmentUserType\n\ngrails.gorm.default.mapping = {\n    "user-type" type: AttachmentUserType, class: Attachment // useful to only require specifying class type in domain\n}\n\nremora {\n    storage {\n        bucket = 'uploads'\n        providerOptions {\n            provider = 'local' // // Switch to s3 if you wish to use s3 and install the karman-aws plugin\n            basePath = 'storage'\n            baseUrl = 'http://localhost:8080/image-test/storage'\n        }\n\n        provider { // corresponds to provider in providerOptions\n            local {\n                basePath = 'storage'\n                baseUrl = 'http://localhost:8080/image-test/storage'\n            }\n\n            s3 {\n                basePath = 'storage'\n                baseUrl = 'http://localhost:8080/image-test/storage'\n                //accessKey = "KEY" //Used for S3 Provider\n                //secretKey = "KEY" //Used for S3 Provider\n            }\n        }\n    }\n}\n\n
\n

The providerOptions section will pass straight through to karmans StorageProvider.create() factory. The provider specifies the storage provider to use while the other options are specific to each provider.

\n

In the above example we are using the karman local storage provider. This is all well and good, but we also need to be able to serve these files from a URL. Depending on your environment this can get a bit tricky.\nOne option is to use nginx to serve the directory and point the baseUrl to the appropriate endpoint. Another option is to use the built in endpoint provided by the karman plugin:

\n

NOTE:

\n

You can also configure which bucket or karman storage provider is used on a per domain level as well as per property level basis in your application config. For example the Book domain class could be configured as follows:

\n
\nremora {\n    domain {\n        book {\n            storage {\n                path = 'uploads/:class/:id/:propertyName/' //This configures the storage path of the files being uploaded by domain class name and property name and identifier in GORM\n                bucket = 'uploads'\n                providerOptions {\n                    provider = 'local' // Switch to s3 if you wish to use s3 and install the karman-aws plugin\n                    basePath = 'storage'\n                    baseUrl  = 'http://localhost:8080/image-test/storage'\n                    //accessKey = "KEY" //Used for S3 Provider\n                    //secretKey = "KEY" //Used for S3 Provider\n                }\n            }\n        }\n    }\n}\n  \n\n
\n

Usage

\n

Unlike its worthy predecessor Selfie, the Remora plugin does not use an embedded GORM domain class to provide an elegant DSL for uploading and attaching files to your domains. You merely only need to add the Attachment class as the type for your storage file. Instead of embedding, aforesaid type becomes a single text field column which is serialized to JSON, instead of multiple columns that would be added if it were embedded.

\n

Example DSL:

\n
import com.neilab.plugins.remora.Attachment\nimport com.neilab.plugins.remora.AttachmentUserType\n\nclass Book {\n  String name\n  Integer size\n  Attachment photo      // only this is require, everything else is optional\n\n  static remora = [\n    photo: [    // if a key is the name of a property and  not reserved (see below), can be used to configure attachments properties\n      styles: [\n        thumb: [width: 50, height: 50, mode: 'fit'],\n        medium: [width: 250, height: 250, mode: 'scale']\n      ]\n    ],\n    \n    storage: [ // reserved key which allows overriding application configs for this domain.\n        bucket:'book_bucket',\n        //:url & :path are interpolated using variables :class,:domainName,:style,:propertyName,:id and :type\n        url: "/:id/:type/:style/:propertyName/",  \n        path: "attachment/:domainName/:propertyName/:id"\n    ],\n    \n    assign: [ // reserved key which allows you to assign the attachment properties to additional model database columns.\n        originalFilename:'name', // assigns filename of original attachment to property :name\n        fileSize:'size' // assigns size of original attachment to property :size\n    ]\n  ]\n   \n  static constraints = {\n    photo contentType: [\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdpng\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd,\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdjpg\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd], fileSize:1024*1024 // 1mb\n  }\n}\n
\n

Uploading Files could not be simpler. Simply use a multipart form and upload a file:

\n
<g:uploadForm name="upload" url="[action:'upload',controller:'photo']">\n  <input type="file" name="photo" /><br/>\n  <g:submitButton name="update" value="Update" /><br/>\n</g:uploadForm>\n
\n

When you bind your params object to your GORM model, the file will automatically be uploaded upon save and processed:

\n
class PhotoController {\n  def upload() {\n    def photo = new Photo(params)\n    if(!photo.save()) {\n      println "Error Saving! ${photo.errors.allErrors}"\n    }\n    redirect view: "index"\n  }\n}\n
\n

Things to be Done

\n\n" }, { "bintrayPackage": { "name": "remote-pagination", "repo": "plugins", "owner": "amitjain", "desc": "Grails remote-pagination plugin", "labels": [ "pagination" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/amitjain1982/remote-pagination/issues", "latestVersion": "0.5.0", "updated": "2016-03-31T13:31:55.155Z", "systemIds": [ "org.grails.plugins:remote-pagination" ], "vcsUrl": "https://github.com/amitjain1982/remote-pagination" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Installation

\n

Just execute following from your application directory:

\n

grails install-plugin remote-pagination

\n

Using

\n

If you have used paginate and sortableColumn tag, then you will find its usage very similar to them. The tags needs to reside inside the template, which renders the list of records. Checkout the Sample Application here.

\n

Config

\n

We can provide default max elements to be displayed for all remote-paginate tags via following configuration. However, it defaults to 10.\n

\n//In Config.groovy\ngrails.plugins.remotepagination.max=20\n//EnableBootstrap here when using twitter bootstrap, default is set to false.\ngrails.plugins.remotepagination.enableBootstrap=true\n

\n

Tags

\n

The remote-pagination plugin currently provides the following tags:

\n\n

util:remotePaginate

\n

Purpose

\n

Creates next/previous buttons and a breadcrumb trail to allow pagination of results, without a page refresh using ajax calls.

\n\n
\n //Example domain class\n  class Book {\n         String title\n         String author\n  }\n  //Example controller used for  all tags:\n  class BookController {\n    def list = {\n       [books: Book.list(params)]\n    }\n    def filter ={\n      render(template:\"listTemplate\" ,model:[ bookInstanceList: Book.list(params )])\n    }        \n  }\n  
\n

\nremotePaginate code written inside _listTemplate.gsp:\n
\n<util:remotePaginate controller=\"book\" action=\"filter\" total=\"${Book.count()}\"\n                                   update=\"listTemplateDivId\" max=\"20\" pageSizes=\"[10, 20, 50,100]\"/>\n<util:remotePaginate controller=\"book\" action=\"filter\" total=\"${Book.count()}\" update=\"listTemplateDivId\"\n                  max=\"20\" pageSizes=\"[10:'10 Per Page', 20: '20 Per Page', 50:'50 Per Page',100:'100 Per Page']\"/>\n
\n### Description\nAttributes update, action and total are required. \n### Attributes\n* total (required) - The total number of results to paginate \n* action (required) - The name of the action to use in the link\n* update (required) - The id of the div/span which contains the tag to render the template, which displays the list.\n* controller (optional) - The name of the controller to use in the link, if not specified the current controller will be linked \n* id (optional) - The id to use in the link \n* params (optional) - A map containing request parameters \n* prev (optional) - The text to display for the previous link (defaults to \"Previous\" as defined by default.paginate.prev property in I18n messages.properties) \n* next (optional) - The text to display for the next link (defaults to \"Next\" as defined by default.paginate.next property in I18n messages.properties) \n* max (optional) - The number of records displayed per page (defaults to 10). Used ONLY if params.max is empty \n* maxsteps (optional) - The number of steps displayed for pagination (defaults to 10). Used ONLY if params.maxsteps is empty \n* offset (optional) - Used ONLY if params.offset is empty\n* pageSizes(optional) - The list containing different page sizes user can select from(defaults to max attribute or the first value given in the list). Provide Map instead of list to display text other than pageSize in a select box.\n* alwaysShowPageSizes(optional) - A boolean value, either to show pageSizes select box irrespective of total records (defaults to false). Use only when pageSizes list or map is provided.\n

Events

\n\n

util:remoteSortableColumn

\n

Purpose

\n

Renders a remote sortable column to support sorting in tables , without a page refresh using ajax calls.

\n

Examples\n

\n<util:remoteSortableColumn property="title" title="Title" update="listTemplateDivId"/>\n<util:remoteSortableColumn property="title" title="Title" style="width: 200px" update="listTemplateDivId"/>\n<util:remoteSortableColumn property="author" defaultOrder="desc" title="author"\ntitleKey="book.author" update="listTemplateDivId"/>\n

\n

Description

\n

Attributes update, action and either title or titleKey are required. When title or titleKey attributes are specified then titleKey takes precedence, resulting in the title caption to be resolved against the message source. In case when the message could not be resolved, the title will be used as title caption.

\n

Attributes

\n\n

Events

\n\n

util:remotePageScroll

\n

Purpose

\n

Renders more records lazily on a click of link, appends them to the existing list of records without a page refresh using ajax calls. This tag needs to be inside a template for example "_listTemplate.gsp".\n
Examples\n

\n//This tag is supported only if application's grails javascript library is set to 'jQuery'.\n<util:remotePageScroll action="filter" total="${total}" update="listTemplateDivId"/>\n<util:remotePageScroll action="filter" total="${total}" update="listTemplateDivId"\ntitle="Show More Records..." max="5" class="anyCSSClass"/>\n

\n

Description

\n

Attributes update, action and total are required. This should reside in a template, which loop through the records to be displayed iteratively.

\n

Attributes

\n\n

Events

\n\n

util:remoteNonStopPageScroll

\n

Purpose

\n

Renders more records lazily on page scroll, appends them to the existing list of records without a page refresh using ajax calls. This tag needs to be inside a template for example "_listTemplate.gsp".

\n

Examples\n

\n//This tag is supported only if application's grails javascript library is set to 'jQuery'.\n//We need to include remoteNonStopPageScroll.js file provided by the plugin for this tag to work.\n<g:javascript plugin="remote-pagination" library="remoteNonStopPageScroll"/>
\n<util:remoteNonStopPageScroll action='filter' total="${total}" update="listTemplateDivId" />\n<util:remoteNonStopPageScroll action='filter' controller="book" total="${total}"\nupdate="listTemplateDivId" heightOffset="10" loadingHtml="loadingGifDivId" />\n

\n

Description

\n

Attributes update, action and total are required. This tag should reside in a template for example "_listTemplate.gsp", which loops through the records to be displayed iteratively.

\n

Attributes

\n\n

Events

\n\n

Version History

\n\n

Roadmap

\n

Issues and improvements for this plugin are maintained here on Codehaus JIRA.

\n" }, { "bintrayPackage": { "name": "remotessh", "repo": "maven", "owner": "vahid", "desc": "Grails RemoteSSH Plugin", "labels": [ "ssh" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/vahidhedayati/RemoteSSH/issues", "latestVersion": "3.0.9", "updated": "2019-04-08T20:09:14.111Z", "systemIds": [ "org.grails.plugins:remotessh" ], "vcsUrl": "https://github.com/vahidhedayati/RemoteSSH" }, "documentationUrl": "https://vahidhedayati.github.io/RemoteSSH/", "mavenMetadataUrl": null, "readme": "

RemoteSSH

\n

Grails RemoteSSH Plugin based on Ganymed SSH-2 library

\n

Side note - similar / related projects

\n\n

Dependency Grails 2:

\n
\tcompile ":remote-ssh:0.14"\n
\n

Grails 2 source

\n

Dependency Grails 3 (build.gradle):

\n
\tcompile "org.grails.plugins:remotessh:3.0.9"\n
\n

Grails 3 source

\n

Documentation

\n

How to use latest revision

\n

Configuration variables

\n

SSHUtil methods and how to use

\n

SshUtilService methods and how to use

\n

Groovy Docs for classes within plugin: methods/usage

\n

Java Docs for classes within plugin: methods/usage

\n

Youtube video walking through 0.14+

\n

Demo site grails 2.4.4 remote-ssh:0.14

\n

Demo site grails 3.0.1 remote-ssh:3.0.1

\n

How to use older revisions

\n

For websocket live ssh connection / interaction:

\n

Check out : jssh

\n" }, { "bintrayPackage": { "name": "rendering", "repo": "plugins", "owner": "grails", "desc": "Grails rendering plugin", "labels": [ "rendering", "image", "pdf" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/gpc/rendering/issues", "latestVersion": "2.0.3", "updated": "2017-01-26T14:00:59.747Z", "systemIds": [ "org.grails.plugins:rendering" ], "vcsUrl": "https://github.com/gpc/rendering" }, "documentationUrl": "https://gpc.github.io/rendering/", "mavenMetadataUrl": null, "readme": "

\"Build

\n

Rendering Grails Plugin

\n

This plugin adds PDF, GIF, PNG and JPEG rendering facilities to Grails applications via the XHTML Renderer library.

\n

Rendering is either done directly via one of the \ufffd\ufffd\ufffd\ufffdformat\ufffd\ufffd\ufffd\ufffdRenderingService services \ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd

\n
ByteArrayOutputStream bytes = pdfRenderingService.render(template: "/pdfs/report", model: [data: data])\n
\n

Or via one of the render\ufffd\ufffd\ufffd\ufffdformat\ufffd\ufffd\ufffd\ufffd() methods added to controllers \ufffd\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd

\n
renderPdf(template: "/pdfs/report", model: [report: reportObject], filename: reportObject.name)\n
\n

Please see the User Guide for more information.

\n

The plugin is released under the Apache License 2.0 and is produced under the Grails Plugin Collective.\nHowever, it does LGPL libraries: XhtmlRenderer and iText.

\n" }, { "bintrayPackage": { "name": "request-tracelog", "repo": "plugins", "owner": "nobeans", "desc": "Grails request-tracelog plugin", "labels": [ "logging" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/nobeans/grails-request-tracelog/issues", "latestVersion": "1.3.0", "updated": "2017-06-14T07:06:41.756Z", "systemIds": [ "org.grails.plugins:request-tracelog" ], "vcsUrl": "https://github.com/nobeans/grails-request-tracelog" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

Request Tracelog Plugin for Grails 3

\n

This is a Grails 3 plugin to get info logs of request.

\n

Installation

\n

In build.gradle:

\n
dependencies {\n    compile "org.grails.plugins:request-tracelog:1.2.0"\n}\n
\n

Usage

\n

All you have to do is to install the plugin.\nOnly in the development environment, three request logs emit as follows:

\n
Before Action\n    Request ID: ServletWebRequest: uri=/myapp/sample/index;client=0:0:0:0:0:0:0:1;session=FBDC27659D49A5EB8C257F25922DA45B\n    Request attributes:\n        applicationContextIdFilter.FILTERED: true\n        characterEncodingFilter.FILTERED: true\n        grailsWebRequestFilter.FILTERED: true\n        hiddenHttpMethodFilter.FILTERED: true\n        metricFilter.FILTERED: true\n        org.grails.ACTION_NAME_ATTRIBUTE: index\n        org.grails.CONTROLLER_NAME_ATTRIBUTE: sample\n        org.grails.RESPONSE_FORMATS: [MimeType { name=*/*,extension=all,parameters=[q:1.0] }]\n        org.grails.WEB_REQUEST: ServletWebRequest: uri=/myapp/sample/index;client=0:0:0:0:0:0:0:1;session=FBDC27659D49A5EB8C257F25922DA45B\n        org.grails.url.match.info: org.grails.web.mapping.mvc.GrailsControllerUrlMappingInfo@4989bb9a\n        org.springframework.web.context.request.async.WebAsyncManager.WEB_ASYNC_MANAGER: org.springframework.web.context.request.async.WebAsyncManager@34ecd5c7\n        org.springframework.web.servlet.DispatcherServlet.CONTEXT: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@9cd25ff: startup date [Fri Apr 17 17:12:42 JST 2015]; root of context hierarchy\n        org.springframework.web.servlet.DispatcherServlet.FLASH_MAP_MANAGER: org.springframework.web.servlet.support.SessionFlashMapManager@57be88bf\n        org.springframework.web.servlet.DispatcherServlet.LOCALE_RESOLVER: org.springframework.web.servlet.i18n.SessionLocaleResolver@3999a99f\n        org.springframework.web.servlet.DispatcherServlet.OUTPUT_FLASH_MAP: [:]\n        org.springframework.web.servlet.DispatcherServlet.THEME_RESOLVER: org.springframework.web.servlet.theme.FixedThemeResolver@454ef3ee\n        org.springframework.web.servlet.DispatcherServlet.THEME_SOURCE: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@9cd25ff: startup date [Fri Apr 17 17:12:42 JST 2015]; root of context hierarchy\n        webRequestLoggingFilter.FILTERED: true\n    Request parameters:\n        action: index\n        controller: sample\n    Session attributes:\n        org.grails.FLASH_SCOPE: [:]\n    Cookies:\n        JSESSIONID: FBDC27659D49A5EB8C257F25922DA45B (domain=null, path=null, maxAge=-1, secure=false, comment=null)\n\nAfter Action (time: 0.009[sec])\n    Request ID: ServletWebRequest: uri=/myapp/sample/index;client=0:0:0:0:0:0:0:1;session=FBDC27659D49A5EB8C257F25922DA45B\n    Request parameters:\n        action: index\n        controller: sample\n    Session attributes:\n        org.grails.FLASH_SCOPE: [:]\n    Cookies:\n        JSESSIONID: FBDC27659D49A5EB8C257F25922DA45B (domain=null, path=null, maxAge=-1, secure=false, comment=null)\n\nAfter View (time: 0.011[sec])\n    Request ID: ServletWebRequest: uri=/myapp/sample/index;client=0:0:0:0:0:0:0:1;session=FBDC27659D49A5EB8C257F25922DA45B\n    Request parameters:\n        action: index\n        controller: sample\n    Session attributes:\n        org.grails.FLASH_SCOPE: [:]\n    Cookies:\n        JSESSIONID: FBDC27659D49A5EB8C257F25922DA45B (domain=null, path=null, maxAge=-1, secure=false, comment=null)\n
\n

Configuration

\n

Logging

\n

You can configure log settings (e.g. log level) by using the following FQCN of the interceptor.

\n
grails.app.controllers.request.tracelog.RequestTracelogInterceptor\n
\n

Code Status

\n

\"Build

\n

License

\n

This is released under the Apache 2.0 License

\n" }, { "bintrayPackage": { "name": "rest-awesome", "repo": "plugins", "owner": "troutbird", "desc": null, "labels": [ "pagination", "rest", "json" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/ejaz-ahmed/grails-rest-awesome-plugin/issues", "latestVersion": "0.2.0", "updated": "2016-03-31T13:31:54.825Z", "systemIds": [ "org.grails.plugins:rest-awesome" ], "vcsUrl": "https://github.com/ejaz-ahmed/grails-rest-awesome-plugin" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

grails-rest-awesome-plugin - Sponsored by SaaSMax

\n

This plugin adds pagination support to the default REST response of grails applications.\nI've plan to add search and include/exclude fields in future.

\n

Installation

\n
compile 'org.grails.plugins:rest-awesome:0.2.0'\n
\n

Using this plugin

\n

This plugin includes a sample application to which can also be referred.

\n

In order to use this plugin, you will have to first register the custom marshaller provided by this plugin.\nIf you have a domain class such as Book as shown below:

\n
class Book {\n    String title\n    Double price\n\n    static constraints = {\n    }\n}\n
\n

You have to register two marshallers for this class (one for collection and one for individual item)

\n

To do so, add following lines to your grails/app/conf/spring/resources.groovy file

\n
import demo.Book\nimport org.grails.plugins.restawesome.renderer.ApiCollectionRendererJson\nimport org.grails.plugins.restawesome.renderer.ApiRendererJson\n\nbeans = {\n    bookRenderer(ApiRendererJson, Book) {\n        label = "book"\n    }\n\n    bookCollectionRenderer(ApiCollectionRendererJson, Book) {\n        label = "books"\n    }\n}\n\n
\n

label is optional. If you provide, it will use the provided label otherwise it has a fallback value which\nis "entity" for individual item and "entities" for collection.

\n

After registering marshallers, you will have to extend "AwesomeRestfulController" provided by this plugin.

\n

Our sample BookController should look like this.

\n
package demo\n\nimport org.grails.plugins.restawesome.AwesomeRestfulController\n\nclass BookController extends AwesomeRestfulController {\n\n    static responseFormats = ['json']\n\n    BookController(){\n        super(Book)\n    }\n}\n
\n

What will you get?

\n

Here is sample output of curl request to this plugin.

\n
curl  http://localhost:8080/book\n{"books":[\n{"class":"demo.Book","id":1,"price":33.2,"title":"Grails in Action"},\n{"class":"demo.Book","id":2,"price":20.2,"title":"Groovy in Action"}],\n"paging":{"totalCount":2,"currentMax":10,"curentOffset":0}}\n
\n

You can also sort this response with any of the attributes of Book class. To sort with price,

\n
curl  http://localhost:8080/book?sort=price\n{"books":[\n{"class":"demo.Book","id":2,"price":20.2,"title":"Groovy in Action"},\n{"class":"demo.Book","id":1,"price":33.2,"title":"Grails in Action"}],\n"paging":{"totalCount":2,"currentMax":10,"curentOffset":0}}\n
\n

We can also change the order of sort like "desc" or "asc".

\n

Sorted by price in descending order:

\n
curl  "http://localhost:8080/book?sort=price&order=desc"\n{"books":[\n{"class":"demo.Book","id":1,"price":33.2,"title":"Grails in Action"},\n{"class":"demo.Book","id":2,"price":20.2,"title":"Groovy in Action"}],\n"paging":{"totalCount":2,"currentMax":10,"curentOffset":0}}\n
\n

Sorted by price in ascending order:

\n
curl  "http://localhost:8080/book?sort=price&order=asc"\n{"books":[\n{"class":"demo.Book","id":2,"price":20.2,"title":"Groovy in Action"},\n{"class":"demo.Book","id":1,"price":33.2,"title":"Grails in Action"}],\n"paging":{"totalCount":2,"currentMax":10,"curentOffset":0}}\n
\n

About SaaSMax

\n

SaaSMAX is the growth engine for SaaS companies and their resellers. Our mission is all about recurring SaaS commissions.

\n" }, { "bintrayPackage": { "name": "retina-tag", "repo": "grails3-plugins", "owner": "bertramlabs", "desc": "Adds retina resolution image tag support for asset-pipeline.", "labels": [ "image", "retina" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/bertramdev/retina-tag-grails/issues", "latestVersion": "3.0.0", "updated": "2017-11-07T07:34:50.354Z", "systemIds": [ "com.bertramlabs.plugins:retina-tag" ], "vcsUrl": "https://github.com/bertramdev/retina-tag-grails" }, "documentationUrl": null, "mavenMetadataUrl": null, "readme": "

RetinaTag

\n

The Grails Retina Tag plugin adds retina tag image support to the asset pipeline <asset:image/> taglib.\nRetinaTag resolves this by extending <asset:image/> to create a hidpi_src attribute with the retina image path if it exists.

\n

Installation

\n

Add retina tag to your build config

\n
plugins {\n\tcompile ':retina-tag:1.1.0'\n}\n
\n

Grals 3

\n
dependencies {\n\tcompile 'com.bertramlabs.plugins:retina-tag:3.0.0'\n}\n
\n

Usage

\n

Add retina_tag.js to your application.js file after including jQuery:

\n
//=require retina_tag\n
\n

Add double pixel resolution images in your assets directory with the @2x modifier

\n
logo.png\nlogo@2x.png\n
\n

Be sure to also specify the base dimensions in your image_tag calls:

\n
<asset:image src='logo.png' height=50/>\n
\n

Awesome right?

\n

Forcing Refresh after loading dynamic content

\n

Retina tag listens to the global event on document called retina_tag:refresh. Firing this event will force retina_tag to rescan the dom for images and update their image src if necessary. Useful if loading content dynamically. Note: retina_tag automatically supports turbolinks.

\n

Override Hidpi src attribute

\n

In some cases it becomes necessary to override the data-hidpi-src attribute and skip asset pipeline. A good example of this might be to load a users profile picture which is stored elsewhere.

\n
\t<asset:image src="${user.photo.url('medium')}" data-hidpi-src="${user.photo.url('medium_2x')" height="75%" width="75"/>\n
\n

Contributing

\n
    \n
  1. Fork it
  2. \n
  3. Create your feature branch (git checkout -b my-new-feature)
  4. \n
  5. Commit your changes (git commit -am 'Added some feature')
  6. \n
  7. Push to the branch (git push origin my-new-feature)
  8. \n
  9. Create new Pull Request
  10. \n
\n

##License\nThis project is licensed under the APACHE License.

\n" }, { "bintrayPackage": { "name": "rx-gorm-rest-client", "repo": "plugins", "owner": "grails", "desc": "Provides a RxGORM Object Mapping implementation for communication with REST web services", "labels": [ "gorm", "json", "rest", "rxjava" ], "licenses": [ "Apache-2.0" ], "issueTrackerUrl": "https://github.com/grails/gorm-rest-client/issues", "latestVersion": "1.1.0.RELEASE", "updated": "2017-03-27T14:02:29.543Z", "systemIds": [ "org.grails.plugins:rx-gorm-rest-client" ], "vcsUrl": "https://github.com/grails/gorm-rest-client" }, "documentationUrl": "http://gorm.grails.org/latest/rx/rest-client/manual/", "mavenMetadataUrl": null, "readme": "

RxGORM REST Client

\n

This project implements RxGORM for REST web services.

\n\n

The snapshot documentation is available here:

\n\n" }, { "comment": "Hard to tell versions to use here. According to https://gorm.grails.org/latest/rx/manual/ it is 7.3.2 but the latest release of this plugin is 6.1