<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>An Army of Solipsists</title>
	<atom:link href="http://burtbeckwith.com/blog/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://burtbeckwith.com/blog</link>
	<description>Burt Beckwith's Java Blog</description>
	<lastBuildDate>Tue, 20 Jul 2010 15:03:50 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Grails App-Info plugin</title>
		<link>http://burtbeckwith.com/blog/?p=344</link>
		<comments>http://burtbeckwith.com/blog/?p=344#comments</comments>
		<pubDate>Sat, 17 Jul 2010 07:38:36 +0000</pubDate>
		<dc:creator>Burt</dc:creator>
				<category><![CDATA[grails]]></category>
		<category><![CDATA[grailsplugin]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[log4j]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://burtbeckwith.com/blog/?p=344</guid>
		<description><![CDATA[I released a new Grails plugin today, app-info. This plugin exposes a lot of internal information for a Grails application. Most of the code for this plugin dates back a long time and was originally mostly JSPs that I would copy into whatever application I was working on to give myself a view into what's [...]]]></description>
			<content:encoded><![CDATA[<p>I released a new <a target='_blank' href='http://grails.org/'>Grails<img src='/blog/images/pop.gif'/></a> plugin today, <a target='_blank' href='http://grails.org/plugin/app-info'>app-info<img src='/blog/images/pop.gif'/></a>. This plugin exposes a lot of internal information for a Grails application. Most of the code for this plugin dates back a long time and was originally mostly JSPs that I would copy into whatever application I was working on to give myself a view into what's going on. Over time as I started using Spring and Hibernate I added more pages to display that information, and it now also shows information about Grails too.</p>
<p>Click any of the images to see the full-size version in a new window.</p>
<h2>Configuration</h2>
<p>This plugin uses the <a target='_blank' href='http://grails.org/plugin/dynamic-controller'>Dynamic Controller plugin<img src='/blog/images/pop.gif'/></a> to modularize the controller actions as mixins. There are several of them and if there are some you don't want or need, you can exclude them. None are configured by default - that has to be done in your application's <code>grails-app/conf/Config.groovy</code> file. Here's the configuration from the sample application (download link at the end):</p>
<div class="syntax_hilite">
<div id="java-2">
<div class="java">grails.<span style="color: #000000;">plugins</span>.<span style="color: #000000;">dynamicController</span>.<span style="color: #000000;">mixins</span> = <span style="color: #000000;">&#91;</span><br />
&nbsp; &nbsp;<span style="color: #0000ff;">'com.burtbeckwith.grails.plugins.appinfo.IndexControllerMixin'</span>:&nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">'com.burtbeckwith.appinfo_test.AdminManageController'</span>,<br />
&nbsp; &nbsp;<span style="color: #0000ff;">'com.burtbeckwith.grails.plugins.appinfo.HibernateControllerMixin'</span>:&nbsp; &nbsp;<span style="color: #0000ff;">'com.burtbeckwith.appinfo_test.AdminManageController'</span>,<br />
&nbsp; &nbsp;<span style="color: #0000ff;">'com.burtbeckwith.grails.plugins.appinfo.Log4jControllerMixin'</span> :&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'com.burtbeckwith.appinfo_test.AdminManageController'</span>,<br />
&nbsp; &nbsp;<span style="color: #0000ff;">'com.burtbeckwith.grails.plugins.appinfo.SpringControllerMixin'</span> :&nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">'com.burtbeckwith.appinfo_test.AdminManageController'</span>,<br />
&nbsp; &nbsp;<span style="color: #0000ff;">'com.burtbeckwith.grails.plugins.appinfo.MemoryControllerMixin'</span> :&nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">'com.burtbeckwith.appinfo_test.AdminManageController'</span>,<br />
&nbsp; &nbsp;<span style="color: #0000ff;">'com.burtbeckwith.grails.plugins.appinfo.PropertiesControllerMixin'</span> : <span style="color: #0000ff;">'com.burtbeckwith.appinfo_test.AdminManageController'</span>,<br />
&nbsp; &nbsp;<span style="color: #0000ff;">'com.burtbeckwith.grails.plugins.appinfo.ScopesControllerMixin'</span> :&nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">'com.burtbeckwith.appinfo_test.AdminManageController'</span><br />
<span style="color: #000000;">&#93;</span></div>
</div>
</div>
<p></p>
<p>With this configuration all of the URLs will start with http://localhost:8080/appname/adminManage. My preference is to re-map these in <code>grails-app/conf/UrlMappings.groovy</code> to http://localhost:8080/appname/admin/manage since I want the administration parts of the application under /admin/**. This is optional but if you want to do this see the configuration in the sample app.</p>
<p><strong>Note:</strong> This plugin exposes a lot of information about your application so you're strongly recommended to use a security plugin and guard these URLs. The sample application uses the <a target='_blank' href='http://grails.org/plugin/spring-security-core'>Spring Security Core<img src='/blog/images/pop.gif'/></a> plugin but you're free to restrict access however you like, and optionally not even include this in your production war.</p>
<h2>Usage</h2>
<hr/>
<p>The <em>Attributes</em> menu has three entries:</p>
<p><strong>Application</strong></p>
<p>Displays all application-scope attributes from the ServletContext</p>
<p><a target='_blank' href='/blog/files/344/application.png'><img src='/blog/files/344/application.small.png' border='0'/></a></p>
<p><strong>Request</strong></p>
<p>Displays all request-scope attributes from the current HttpServletRequest. Since this is for the current request, it's mostly useful to see what's available in a typical request.</p>
<p><a target='_blank' href='/blog/files/344/request.png'><img src='/blog/files/344/request.small.png' border='0'/></a></p>
<p><strong>Session</strong></p>
<p>Displays all session-scope attributes from the current HttpSession. Since this is for the current request, it's mostly useful to see what's available in a typical session.</p>
<p><a target='_blank' href='/blog/files/344/session.png'><img src='/blog/files/344/session.small.png' border='0'/></a></p>
<hr/>
<p>The <em>Properties</em> menu has three entries:</p>
<p><strong>Data Source</strong></p>
<p>A read/write view of the DataSource bean. Depending on the DataSource implementation, changing an attribute will take effect immediately and reset the connection pool</p>
<p><a target='_blank' href='/blog/files/344/datasource.png'><img src='/blog/files/344/datasource.small.png' border='0'/></a></p>
<p><strong>Grails Properties</strong></p>
<p>Read-only view of the Grails Configuration.</p>
<p><a target='_blank' href='/blog/files/344/grailsproperties.png'><img src='/blog/files/344/grailsproperties.small.png' border='0'/></a></p>
<p><strong>System Properties</strong></p>
<p>Read/write view of system properties. You can alter current properties or add new ones.</p>
<p><a target='_blank' href='/blog/files/344/systemproperties.png'><img src='/blog/files/344/systemproperties.small.png' border='0'/></a></p>
<hr/>
<p>The <em>Info</em> menu has five entries:</p>
<p><strong>Controllers</strong></p>
<p>All controllers, plus links to all actions</p>
<p><a target='_blank' href='/blog/files/344/controllers.png'><img src='/blog/files/344/controllers.small.png' border='0'/></a></p>
<p><strong>Logging</strong></p>
<p>Has comboboxes for all loggers to change the log level at runtime. Also has a text field to register a new Logger and its level.</p>
<p>Also includes a reverse-engineered log4j.xml based on the in-memory Log4j configuration. This is an estimate, so it may not be 100% accurate. But if you're having logging configuration issues and are familiar with the log4j.xml format, this can be convenient for diagnosing how things are misconfigured.</p>
<p><a target='_blank' href='/blog/files/344/logging.png'><img src='/blog/files/344/logging.small.png' border='0'/></a></p>
<p><strong>Memory</strong></p>
<p>Graphs describing memory usage. Also has an action to trigger explicit garbage collection.</p>
<p><a target='_blank' href='/blog/files/344/memory.png'><img src='/blog/files/344/memory.small.png' border='0'/></a></p>
<p><strong>Sessions</strong></p>
<p>Displays all current sessions and session-scope variables with a link to invalidate the session. This is enabled by default; to disable set <code>grails.plugins.appinfo.useContextListener = false<code> in <code>grails-app/conf/Config.groovy<code></p>
<p><a target='_blank' href='/blog/files/344/sessions.png'><img src='/blog/files/344/sessions.small.png' border='0'/></a></p>
<p><strong>Spring Beans</strong></p>
<p>Spring bean information for all beans in the "main" context and the parent context</p>
<p><a target='_blank' href='/blog/files/344/spring.png'><img src='/blog/files/344/spring.small.png' border='0'/></a></p>
<hr/>
<p>The <em>Hibernate</em> menu has five entries and several sub-actions</p>
<p><strong>Overview</strong></p>
<ul>
<li>Properties</li>
<li>Mappings Info</li>
<li>Imports</li>
<li>Auxiliary Database Objects</li>
<li>Named Queries</li>
<li>Named SQL Queries</li>
<li>TypeDefs</li>
<li>Filter Definitions</li>
</ul>
<p><a target='_blank' href='/blog/files/344/hibernate.overview.png'><img src='/blog/files/344/hibernate.overview.small.png' border='0'/></a></p>
<p><strong>Entity Graphs</strong></p>
<p>ER-style graphs of all Hibernate classes with relationships.</p>
<p><a target='_blank' href='/blog/files/344/hibernate.entitygraph.png'><img src='/blog/files/344/hibernate.entitygraph.small.png' border='0'/></a></p>
<p><strong>Table Graphs</strong></p>
<p>ER-style graphs of all tables with relationships.</p>
<p><a target='_blank' href='/blog/files/344/hibernate.tablegraph.png'><img src='/blog/files/344/hibernate.tablegraph.small.png' border='0'/></a></p>
<p><strong>Caching</strong></p>
<p>2<sup>nd</sup>-level cache information for StandardQueryCache, UpdateTimestampsCache, and all domain class caches.</p>
<p><a target='_blank' href='/blog/files/344/hibernate.cache.png'><img src='/blog/files/344/hibernate.cache.small.png' border='0'/></a></p>
<p>Also has links to clear the cache and display usage graphs</p>
<p><a target='_blank' href='/blog/files/344/hibernate.cache.graph.png'><img src='/blog/files/344/hibernate.cache.graph.small.png' border='0'/></a></p>
<p><strong>Statistics</strong></p>
<ul>
<li>General Hibernate statistics</li>
<li>Links for statistics for each domain class</li>
<li>Links for statistics for each collection</li>
<li>Links for statistics for cached queries</li>
</ul>
<p><a target='_blank' href='/blog/files/344/hibernate.stats.png'><img src='/blog/files/344/hibernate.stats.small.png' border='0'/></a></p>
<p><strong>Combos</strong></p>
<p>On each page there are three combo boxes. The <em>Tables</em> combo box lists all database tables and selecting one displays detailed information for that table</p>
<p><a target='_blank' href='/blog/files/344/hibernate.table.png'><img src='/blog/files/344/hibernate.table.small.png' border='0'/></a></p>
<p>The <em>Entities</em> combo box lists all entities (domain classes, JPA-annotated Java classes, and hbm.xml-mapped classes) and selecting one displays detailed information for each one</p>
<p><a target='_blank' href='/blog/files/344/hibernate.entry.png'><img src='/blog/files/344/hibernate.entry.small.png' border='0'/></a></p>
<p>The <em>hbm.xml</em> combo box lists all entities and selecting one displays the reverse-engineered hbm.xml that would have created the equivalent entity. This is useful if you're having GORM mapping issues and want to see what the Hibernate configuration is</p>
<p><a target='_blank' href='/blog/files/344/hibernate.hbm.png'><img src='/blog/files/344/hibernate.hbm.small.png' border='0'/></a></p>
<h2>Sample Project</h2>
<p>You can download a preconfigured sample application <a target='_blank' href='/blog/files/344/appinfo-test.zip'>here<img src='/blog/images/pop.gif'/></a></p>
<p>The /admin/** URLs in the sample app are restricted to users with ROLE_ADMIN. There's one user configured in BootStrap.groovy with username 'admin' and password 'password' with ROLE_ADMIN, so you can use that to authenticate.</p>
]]></content:encoded>
			<wfw:commentRss>http://burtbeckwith.com/blog/?feed=rss2&amp;p=344</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Using GMail with a Log4j SMTP Appender in Grails</title>
		<link>http://burtbeckwith.com/blog/?p=329</link>
		<comments>http://burtbeckwith.com/blog/?p=329#comments</comments>
		<pubDate>Thu, 04 Feb 2010 03:55:27 +0000</pubDate>
		<dc:creator>Burt</dc:creator>
				<category><![CDATA[grails]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[log4j]]></category>

		<guid isPermaLink="false">http://burtbeckwith.com/blog/?p=329</guid>
		<description><![CDATA[I saw a plaintive wail on Twitter about using GMail as the smtp server to send error emails using a Log4j SMTPAppender in Grails. It turned out to be a little tricky (and a bigger solution than 140 characters would allow) so I thought I'd describe the process here.
Most of the properties are configurable as [...]]]></description>
			<content:encoded><![CDATA[<p>I saw a <a target='_blank' href='http://twitter.com/scottdavis99/status/8609740391'>plaintive wail<img src='/blog/images/pop.gif'/></a> on Twitter about using GMail as the smtp server to send error emails using a <a target='_blank' href='http://logging.apache.org/log4j/'>Log4j<img src='/blog/images/pop.gif'/></a> <a target='_blank' href='http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/net/SMTPAppender.html'>SMTPAppender<img src='/blog/images/pop.gif'/></a> in <a target='_blank' href='http://grails.org/'>Grails<img src='/blog/images/pop.gif'/></a>. It turned out to be a little tricky (and a bigger solution than 140 characters would allow) so I thought I'd describe the process here.</p>
<p>Most of the properties are configurable as appender attributes (e.g. server name, auth username, etc.) but two important ones aren't. <code>SMTPAppender</code> creates a <code>Properties</code> instance with <code>System.getProperties()</code> as the default values and adds smtp properties to that. But you need to specify the smtp port (it will default to 25 otherwise) and you need to tell it to send a <code>STARTTLS</code> command. Both are configurable via system properties:</p>
<div class="syntax_hilite">
<div id="java-5">
<div class="java"><a href="http://www.google.com/search?q=allinurl%3ASystem+java.sun.com&amp;bntl=1"><span style="color: #000000;">System</span></a>.<span style="color: #000000;">setProperty</span> <span style="color: #0000ff;">'mail.smtp.port'</span>, <span style="color: #0000ff;">'587'</span><br />
<a href="http://www.google.com/search?q=allinurl%3ASystem+java.sun.com&amp;bntl=1"><span style="color: #000000;">System</span></a>.<span style="color: #000000;">setProperty</span> <span style="color: #0000ff;">'mail.smtp.starttls.enable'</span>, <span style="color: #0000ff;">'true'</span></div>
</div>
</div>
<p></p>
<p>and if you add those calls to <code>Config.groovy</code> before the appender is instantiated then it will have the values available when it configures its JavaMail <code>Session</code>:</p>
<div class="syntax_hilite">
<div id="java-6">
<div class="java"><span style="color: #3333ff;">import org.apache.log4j.Level</span><br />
<span style="color: #3333ff;">import org.apache.log4j.net.SMTPAppender</span></p>
<p>...</p>
<p><span style="color: #000000;">mail</span>.<span style="color: #000000;">error</span>.<span style="color: #000000;">server</span> = <span style="color: #0000ff;">'smtp.gmail.com'</span><br />
mail.<span style="color: #000000;">error</span>.<span style="color: #000000;">port</span> = <span style="color: #000000;">587</span><br />
mail.<span style="color: #000000;">error</span>.<span style="color: #000000;">username</span> = <span style="color: #0000ff;">'your.email@gmail.com'</span><br />
mail.<span style="color: #000000;">error</span>.<span style="color: #000000;">password</span> = <span style="color: #0000ff;">'yourpassword'</span><br />
mail.<span style="color: #000000;">error</span>.<span style="color: #000000;">to</span> = <span style="color: #0000ff;">'to@yourapp.com'</span><br />
mail.<span style="color: #000000;">error</span>.<span style="color: #000000;">from</span> = <span style="color: #0000ff;">'from@yourapp.com'</span><br />
mail.<span style="color: #000000;">error</span>.<span style="color: #000000;">subject</span> = <span style="color: #0000ff;">'[Application Error]'</span><br />
mail.<span style="color: #000000;">error</span>.<span style="color: #000000;">starttls</span> = <span style="color: #000099; font-weight: bold;">true</span><br />
mail.<span style="color: #000000;">error</span>.<span style="color: #000000;">debug</span> = <span style="color: #000099; font-weight: bold;">false</span></p>
<p>environments <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp;production <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; grails.<span style="color: #000000;">serverURL</span> = <span style="color: #0000ff;">"http://www.changeme.com"</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span><br />
&nbsp; &nbsp;development <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; grails.<span style="color: #000000;">serverURL</span> = <span style="color: #0000ff;">"http://localhost:8080/${appName}"</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span><br />
&nbsp; &nbsp;test <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; grails.<span style="color: #000000;">serverURL</span> = <span style="color: #0000ff;">"http://localhost:8080/${appName}"</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span><br />
<span style="color: #000000;">&#125;</span></p>
<p>log4j = <span style="color: #000000;">&#123;</span></p>
<p>&nbsp; &nbsp;<a href="http://www.google.com/search?q=allinurl%3ASystem+java.sun.com&amp;bntl=1"><span style="color: #000000;">System</span></a>.<span style="color: #000000;">setProperty</span> <span style="color: #0000ff;">'mail.smtp.port'</span>, mail.<span style="color: #000000;">error</span>.<span style="color: #000000;">port</span>.<span style="color: #000000;">toString</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;<a href="http://www.google.com/search?q=allinurl%3ASystem+java.sun.com&amp;bntl=1"><span style="color: #000000;">System</span></a>.<span style="color: #000000;">setProperty</span> <span style="color: #0000ff;">'mail.smtp.starttls.enable'</span>, mail.<span style="color: #000000;">error</span>.<span style="color: #000000;">starttls</span>.<span style="color: #000000;">toString</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span></p>
<p>&nbsp; &nbsp;appenders <span style="color: #000000;">&#123;</span></p>
<p>&nbsp; &nbsp; &nbsp; appender <span style="color: #000099; font-weight: bold;">new</span> SMTPAppender<span style="color: #000000;">&#40;</span>name: <span style="color: #0000ff;">'smtp'</span>, to: mail.<span style="color: #000000;">error</span>.<span style="color: #000000;">to</span>, from: mail.<span style="color: #000000;">error</span>.<span style="color: #000000;">from</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;subject: mail.<span style="color: #000000;">error</span>.<span style="color: #000000;">subject</span>, threshold: Level.<span style="color: #000000;">ERROR</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;SMTPHost: mail.<span style="color: #000000;">error</span>.<span style="color: #000000;">server</span>, SMTPUsername: mail.<span style="color: #000000;">error</span>.<span style="color: #000000;">username</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;SMTPDebug: mail.<span style="color: #000000;">error</span>.<span style="color: #000000;">debug</span>.<span style="color: #000000;">toString</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>, SMTPPassword: mail.<span style="color: #000000;">error</span>.<span style="color: #000000;">password</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;layout: pattern<span style="color: #000000;">&#40;</span>conversionPattern:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'%d{[ dd.MM.yyyy HH:mm:ss.SSS]} [%t] %n%-5p %n%c %n%C %n %x %n %m%n'</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;error&nbsp; <span style="color: #0000ff;">'org.codehaus.groovy.grails.web.servlet'</span>,&nbsp; <span style="color: #116611; font-style: italic;">//&nbsp; controllers</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'org.codehaus.groovy.grails.web.pages'</span>, <span style="color: #116611; font-style: italic;">//&nbsp; GSP</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'org.codehaus.groovy.grails.web.sitemesh'</span>, <span style="color: #116611; font-style: italic;">//&nbsp; layouts</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'org.codehaus.groovy.grails.web.mapping.filter'</span>, <span style="color: #116611; font-style: italic;">// URL mapping</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'org.codehaus.groovy.grails.web.mapping'</span>, <span style="color: #116611; font-style: italic;">// URL mapping</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'org.codehaus.groovy.grails.commons'</span>, <span style="color: #116611; font-style: italic;">// core / classloading</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'org.codehaus.groovy.grails.plugins'</span>, <span style="color: #116611; font-style: italic;">// plugins</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'org.codehaus.groovy.grails.orm.hibernate'</span>, <span style="color: #116611; font-style: italic;">// hibernate integration</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'org.springframework'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'org.hibernate'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'net.sf.ehcache.hibernate'</span><br />
&nbsp; &nbsp;warn&nbsp; &nbsp;<span style="color: #0000ff;">'org.mortbay.log'</span></p>
<p>&nbsp; &nbsp;root <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; error <span style="color: #0000ff;">'stdout'</span>, <span style="color: #0000ff;">'smtp'</span><br />
&nbsp; &nbsp; &nbsp; additivity = <span style="color: #000099; font-weight: bold;">true</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span><br />
<span style="color: #000000;">&#125;</span></div>
</div>
</div>
<p></p>
<p>I've parameterized the properties to make them configurable for each environment or using an external configuration file.</p>
<p>Note that GMail has a limit of 500 emails per day, so if you generate a lot of errors in your app you could hit that limit.</p>
]]></content:encoded>
			<wfw:commentRss>http://burtbeckwith.com/blog/?feed=rss2&amp;p=329</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Delayed SessionFactory Creation in Grails</title>
		<link>http://burtbeckwith.com/blog/?p=312</link>
		<comments>http://burtbeckwith.com/blog/?p=312#comments</comments>
		<pubDate>Mon, 25 Jan 2010 06:04:22 +0000</pubDate>
		<dc:creator>Burt</dc:creator>
				<category><![CDATA[gorm]]></category>
		<category><![CDATA[grails]]></category>
		<category><![CDATA[hibernate]]></category>
		<category><![CDATA[java]]></category>

		<guid isPermaLink="false">http://burtbeckwith.com/blog/?p=312</guid>
		<description><![CDATA[The topic of delaying DataSource and SessionFactory creation until some point after startup has come up a few times on the Grails user mailing list so I thought I'd give it a shot. I got it working, but it's not pretty.
Grails (and Hibernate) will create up to three connections during initialization so the primary focus [...]]]></description>
			<content:encoded><![CDATA[<p>The topic of delaying <code>DataSource</code> and <code>SessionFactory</code> creation until some point after startup has come up a few times on the <a target='_blank' href='http://grails.org/'>Grails<img src='/blog/images/pop.gif'/></a> user mailing list so I thought I'd give it a shot. I got it working, but it's not pretty.</p>
<p>Grails (and Hibernate) will create up to three connections during initialization so the primary focus is to avoid those. In addition the <code>DataSource</code> will pre-instantiate connections, so we'll delay those as well.</p>
<p>The first connection required is for <code>HibernateDialectDetectorFactoryBean</code>, which uses connection metadata to figure out the dialect if it's not specified. This is a cool feature but problematic if you don't want early access to the database, and luckily the fix is simple: specify the dialect class in <code>DataSource.groovy</code>:</p>
<div class="syntax_hilite">
<div id="java-15">
<div class="java">dataSource <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp;pooled = ...<br />
&nbsp; &nbsp;<span style="color: #000000;">driverClassName</span> = ...<br />
&nbsp; &nbsp;<span style="color: #000000;">username</span> = ...<br />
&nbsp; &nbsp;<span style="color: #000000;">password</span> = ...<br />
&nbsp; &nbsp;<span style="color: #000000;">dialect</span> = org.<span style="color: #000000;">hibernate</span>.<span style="color: #000000;">dialect</span>.<span style="color: #000000;">MySQLInnoDBDialect</span><br />
<span style="color: #000000;">&#125;</span></div>
</div>
</div>
<p></p>
<p>substituting the appropriate class name for your database.</p>
<p>The second connection will be for <code>SpringLobHandlerDetectorFactoryBean</code>, which uses connection metadata to determine if you're using Oracle and if so to use an Oracle-specific <code>LobHandler</code>. The fix here is also simple: override the <code>lobHandlerDetector</code> bean in <code>grails-app/conf/spring/resources.groovy</code> with the correct version for your database. It's a little different if you're using Oracle or another database.</p>
<p>If you're not using Oracle, redefine the bean as</p>
<div class="syntax_hilite">
<div id="java-16">
<div class="java"><span style="color: #3333ff;">import org.springframework.jdbc.support.lob.DefaultLobHandler</span></p>
<p>beans = <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp;lobHandlerDetector<span style="color: #000000;">&#40;</span>DefaultLobHandler<span style="color: #000000;">&#41;</span><br />
<span style="color: #000000;">&#125;</span></div>
</div>
</div>
<p></p>
<p>and if you are, define it as</p>
<div class="syntax_hilite">
<div id="java-17">
<div class="java"><span style="color: #3333ff;">import org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor</span><br />
<span style="color: #3333ff;">import org.springframework.jdbc.support.lob.OracleLobHandler</span></p>
<p>beans = <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp;lobHandlerDetector<span style="color: #000000;">&#40;</span>OracleLobHandler<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; nativeJdbcExtractor = <span style="color: #000099; font-weight: bold;">new</span> CommonsDbcpNativeJdbcExtractor<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span><br />
<span style="color: #000000;">&#125;</span></div>
</div>
</div>
<p></p>
<p>and omit specifying <code>nativeJdbcExtractor</code> if you're not using pooled connections (e.g. if you're using JNDI).</p>
<p>The third connection is for Hibernate and is used to initialize the <code>Configuration</code>. This one is more work and requires some custom code. It's also somewhat brittle in that it requires a copy/paste of the <code>sessionFactory</code> bean definition from Grails source with some modifications, so it will probably require changes to work with future version of Grails.</p>
<p>Here's the override for Grails 1.2:</p>
<div class="syntax_hilite">
<div id="java-18">
<div class="java"><span style="color: #3333ff;">import org.codehaus.groovy.grails.orm.hibernate.events.PatchedDefaultFlushEventListener</span><br />
<span style="color: #3333ff;">import com.burtbeckwith.grails.delayds.DelayedSessionFactoryBean</span><br />
...<br />
<span style="color: #000000;">sessionFactory</span><span style="color: #000000;">&#40;</span>DelayedSessionFactoryBean<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp;def application = AH.<span style="color: #000000;">application</span><br />
&nbsp; &nbsp;def ds = application.<span style="color: #000000;">config</span>.<span style="color: #000000;">dataSource</span><br />
&nbsp; &nbsp;def hibConfig = application.<span style="color: #000000;">config</span>.<span style="color: #000000;">hibernate</span><br />
&nbsp; &nbsp;dataSource = ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'dataSource'</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;<a href="http://www.google.com/search?q=allinurl%3AList+java.sun.com&amp;bntl=1"><span style="color: #000000;">List</span></a> hibConfigLocations = <span style="color: #000000;">&#91;</span><span style="color: #000000;">&#93;</span><br />
&nbsp; &nbsp;<span style="color: #0000ff;">if</span> <span style="color: #000000;">&#40;</span>application.<span style="color: #000000;">classLoader</span>.<span style="color: #000000;">getResource</span><span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'hibernate.cfg.xml'</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; hibConfigLocations &lt;&lt;<span style="color: #0000ff;">'classpath:hibernate.cfg.xml'</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span><br />
&nbsp; &nbsp;def explicitLocations = hibConfig?.<span style="color: #000000;">config</span>?.<span style="color: #000000;">location</span><br />
&nbsp; &nbsp;<span style="color: #0000ff;">if</span> <span style="color: #000000;">&#40;</span>explicitLocations<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #000000;">&#40;</span>explicitLocations <span style="color: #000099; font-weight: bold;">instanceof</span> <a href="http://www.google.com/search?q=allinurl%3ACollection+java.sun.com&amp;bntl=1"><span style="color: #000000;">Collection</span></a><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;hibConfigLocations.<span style="color: #000000;">addAll</span><span style="color: #000000;">&#40;</span>explicitLocations.<span style="color: #000000;">collect</span> <span style="color: #000000;">&#123;</span> it.<span style="color: #000000;">toString</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#125;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">else</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;hibConfigLocations &lt;&lt;hibConfig.<span style="color: #000000;">config</span>.<span style="color: #000000;">location</span>.<span style="color: #000000;">toString</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span><br />
&nbsp; &nbsp;configLocations = hibConfigLocations<br />
&nbsp; &nbsp;<span style="color: #0000ff;">if</span> <span style="color: #000000;">&#40;</span>ds.<span style="color: #000000;">configClass</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; configClass = ds.<span style="color: #000000;">configClass</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span><br />
&nbsp; &nbsp;hibernateProperties = ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'hibernateProperties'</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;grailsApplication = ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'grailsApplication'</span>, <span style="color: #000099; font-weight: bold;">true</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;lobHandler = ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'lobHandlerDetector'</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;entityInterceptor = ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'entityInterceptor'</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;eventListeners = <span style="color: #000000;">&#91;</span><span style="color: #0000ff;">'flush'</span>:&nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #000099; font-weight: bold;">new</span> PatchedDefaultFlushEventListener<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">'pre-load'</span>:&nbsp; &nbsp; ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'eventTriggeringInterceptor'</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">'post-load'</span>:&nbsp; &nbsp;ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'eventTriggeringInterceptor'</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">'save'</span>:&nbsp; &nbsp; &nbsp; &nbsp; ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'eventTriggeringInterceptor'</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">'save-update'</span>: ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'eventTriggeringInterceptor'</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">'post-insert'</span>: ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'eventTriggeringInterceptor'</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">'pre-update'</span>:&nbsp; ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'eventTriggeringInterceptor'</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">'post-update'</span>: ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'eventTriggeringInterceptor'</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">'pre-delete'</span>:&nbsp; ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'eventTriggeringInterceptor'</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">'post-delete'</span>: ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'eventTriggeringInterceptor'</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#93;</span><br />
<span style="color: #000000;">&#125;</span></div>
</div>
</div>
<p></p>
<p>and here's the override for 1.1:</p>
<div class="syntax_hilite">
<div id="java-19">
<div class="java"><span style="color: #3333ff;">import com.burtbeckwith.grails.delayds.DelayedSessionFactoryBean</span><br />
...<br />
<span style="color: #000000;">sessionFactory</span><span style="color: #000000;">&#40;</span>DelayedSessionFactoryBean<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp;def application = AH.<span style="color: #000000;">application</span><br />
&nbsp; &nbsp;def ds = application.<span style="color: #000000;">config</span>.<span style="color: #000000;">dataSource</span><br />
&nbsp; &nbsp;dataSource = ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'dataSource'</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;<span style="color: #0000ff;">if</span> <span style="color: #000000;">&#40;</span>application.<span style="color: #000000;">classLoader</span>.<span style="color: #000000;">getResource</span><span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'hibernate.cfg.xml'</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; configLocation = <span style="color: #0000ff;">'classpath:hibernate.cfg.xml'</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span><br />
&nbsp; &nbsp;<span style="color: #0000ff;">if</span> <span style="color: #000000;">&#40;</span>ds.<span style="color: #000000;">configClass</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; configClass = ds.<span style="color: #000000;">configClass</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span><br />
&nbsp; &nbsp;hibernateProperties = ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'hibernateProperties'</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;grailsApplication = ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'grailsApplication'</span>, <span style="color: #000099; font-weight: bold;">true</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;lobHandler = ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'lobHandlerDetector'</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;eventListeners = <span style="color: #000000;">&#91;</span><span style="color: #0000ff;">'pre-load'</span>:&nbsp; &nbsp; ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'eventTriggeringInterceptor'</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">'post-load'</span>:&nbsp; &nbsp;ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'eventTriggeringInterceptor'</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">'save'</span>:&nbsp; &nbsp; &nbsp; &nbsp; ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'eventTriggeringInterceptor'</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">'save-update'</span>: ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'eventTriggeringInterceptor'</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">'post-insert'</span>: ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'eventTriggeringInterceptor'</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">'pre-update'</span>:&nbsp; ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'eventTriggeringInterceptor'</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">'post-update'</span>: ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'eventTriggeringInterceptor'</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">'pre-delete'</span>:&nbsp; ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'eventTriggeringInterceptor'</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">'post-delete'</span>: ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'eventTriggeringInterceptor'</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#93;</span><br />
<span style="color: #000000;">&#125;</span></div>
</div>
</div>
<p></p>
<p><code>DelayedSessionFactoryBean</code> extends <code>ConfigurableLocalSessionFactoryBean</code> to create a wrapper for the <code>SessionFactory</code> that lazily creates the real <code>SessionFactory</code>. Add this to <code>src/groovy</code>:</p>
<div class="syntax_hilite">
<div id="java-20">
<div class="java">package com.<span style="color: #000000;">burtbeckwith</span>.<span style="color: #000000;">grails</span>.<span style="color: #000000;">delayds</span></p>
<p><span style="color: #3333ff;">import java.lang.reflect.Field</span><br />
<span style="color: #3333ff;">import java.lang.reflect.InvocationHandler</span><br />
<span style="color: #3333ff;">import java.lang.reflect.Method</span><br />
<span style="color: #3333ff;">import java.lang.reflect.Proxy</span></p>
<p><span style="color: #3333ff;">import org.codehaus.groovy.grails.orm.hibernate.ConfigurableLocalSessionFactoryBean</span><br />
<span style="color: #3333ff;">import org.hibernate.SessionFactory</span><br />
<span style="color: #3333ff;">import org.springframework.util.ReflectionUtils</span></p>
<p><span style="color: #000099; font-weight: bold;">class</span> DelayedSessionFactoryBean <span style="color: #000099; font-weight: bold;">extends</span> ConfigurableLocalSessionFactoryBean <span style="color: #000000;">&#123;</span></p>
<p>&nbsp; &nbsp;<span style="color: #000099; font-weight: bold;">private</span> <span style="color: #0000ff;">boolean</span> _initialized<br />
&nbsp; &nbsp;<span style="color: #000099; font-weight: bold;">private</span> SessionFactory _realSessionFactory</p>
<p>&nbsp; &nbsp;@Override<br />
&nbsp; &nbsp;<span style="color: #0000ff;">void</span> afterPropertiesSet<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #116611; font-style: italic;">// do nothing for now, lazy init on first access</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;@Override<br />
&nbsp; &nbsp;SessionFactory getObject<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span></p>
<p>&nbsp; &nbsp; &nbsp; def invoke = <span style="color: #000000;">&#123;</span> proxy, <a href="http://www.google.com/search?q=allinurl%3AMethod+java.sun.com&amp;bntl=1"><span style="color: #000000;">Method</span></a> method, <a href="http://www.google.com/search?q=allinurl%3AObject+java.sun.com&amp;bntl=1"><span style="color: #000000;">Object</span></a><span style="color: #000000;">&#91;</span><span style="color: #000000;">&#93;</span> args -&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;initialize<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #990000;">return</span> method.<span style="color: #000000;">invoke</span><span style="color: #000000;">&#40;</span>_realSessionFactory, args<span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; <span style="color: #990000;">return</span> <a href="http://www.google.com/search?q=allinurl%3AProxy+java.sun.com&amp;bntl=1"><span style="color: #000000;">Proxy</span></a>.<span style="color: #000000;">newProxyInstance</span><span style="color: #000000;">&#40;</span>SessionFactory.<span style="color: #000000;">classLoader</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#91;</span>SessionFactory<span style="color: #000000;">&#93;</span> as <span style="color: #000099; font-weight: bold;">Class</span><span style="color: #000000;">&#91;</span><span style="color: #000000;">&#93;</span>, <span style="color: #000000;">&#91;</span>invoke: invoke<span style="color: #000000;">&#93;</span> as <a href="http://www.google.com/search?q=allinurl%3AInvocationHandler+java.sun.com&amp;bntl=1"><span style="color: #000000;">InvocationHandler</span></a><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;<span style="color: #000099; font-weight: bold;">private</span> <span style="color: #000099; font-weight: bold;">synchronized</span> <span style="color: #0000ff;">void</span> initialize<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #000000;">&#40;</span>_initialized<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #990000;">return</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; _realSessionFactory = wrapSessionFactoryIfNecessary<span style="color: #000000;">&#40;</span>buildSessionFactory<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span></p>
<p>&nbsp; &nbsp; &nbsp; <a href="http://www.google.com/search?q=allinurl%3AField+java.sun.com&amp;bntl=1"><span style="color: #000000;">Field</span></a> field = ReflectionUtils.<span style="color: #000000;">findField</span><span style="color: #000000;">&#40;</span>getClass<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>, <span style="color: #0000ff;">'sessionFactory'</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; field.<span style="color: #000000;">accessible</span> = <span style="color: #000099; font-weight: bold;">true</span><br />
&nbsp; &nbsp; &nbsp; field.<span style="color: #000000;">set</span><span style="color: #000000;">&#40;</span><span style="color: #000099; font-weight: bold;">this</span>, _realSessionFactory<span style="color: #000000;">&#41;</span></p>
<p>&nbsp; &nbsp; &nbsp; afterSessionFactoryCreation<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span></p>
<p>&nbsp; &nbsp; &nbsp; _initialized = <span style="color: #000099; font-weight: bold;">true</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span><br />
<span style="color: #000000;">&#125;</span></div>
</div>
</div>
<p></p>
<p>To delay <code>DataSource</code> creation, we'll use Spring's <code>DelegatingDataSource</code> and build the actual <code>DataSource</code> from the values in <code>grails-app/conf/DataSource.groovy</code> the first time <code>getConnection()</code> is called:</p>
<div class="syntax_hilite">
<div id="java-21">
<div class="java">package com.<span style="color: #000000;">burtbeckwith</span>.<span style="color: #000000;">grails</span>.<span style="color: #000000;">delayds</span></p>
<p><span style="color: #3333ff;">import java.sql.Connection</span><br />
<span style="color: #3333ff;">import java.sql.SQLException</span></p>
<p><span style="color: #3333ff;">import org.apache.commons.dbcp.BasicDataSource</span><br />
<span style="color: #3333ff;">import org.codehaus.groovy.grails.commons.ConfigurationHolder as CH</span><br />
<span style="color: #3333ff;">import org.springframework.jdbc.datasource.DelegatingDataSource</span></p>
<p><span style="color: #000099; font-weight: bold;">class</span> DelayedDataSource <span style="color: #000099; font-weight: bold;">extends</span> DelegatingDataSource <span style="color: #000000;">&#123;</span></p>
<p>&nbsp; &nbsp;<span style="color: #000099; font-weight: bold;">private</span> <span style="color: #0000ff;">boolean</span> _initialized</p>
<p>&nbsp; &nbsp;@Override<br />
&nbsp; &nbsp;<a href="http://www.google.com/search?q=allinurl%3AConnection+java.sun.com&amp;bntl=1"><span style="color: #000000;">Connection</span></a> getConnection<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span> <span style="color: #000099; font-weight: bold;">throws</span> <a href="http://www.google.com/search?q=allinurl%3ASQLException+java.sun.com&amp;bntl=1"><span style="color: #000000;">SQLException</span></a> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; initialize<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #990000;">return</span> super.<span style="color: #000000;">getConnection</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span><br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;@Override<br />
&nbsp; &nbsp;<span style="color: #0000ff;">void</span> afterPropertiesSet<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #116611; font-style: italic;">// override to not check for targetDataSource since it's lazily created</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;<span style="color: #000099; font-weight: bold;">private</span> <span style="color: #000099; font-weight: bold;">synchronized</span> <span style="color: #0000ff;">void</span> initialize<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #000000;">&#40;</span>_initialized<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #990000;">return</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; def config = CH.<span style="color: #000000;">config</span>.<span style="color: #000000;">dataSource</span><br />
&nbsp; &nbsp; &nbsp; setTargetDataSource<span style="color: #000000;">&#40;</span><span style="color: #000099; font-weight: bold;">new</span> BasicDataSource<span style="color: #000000;">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; driverClassName: config.<span style="color: #000000;">driverClassName</span>, password: config.<span style="color: #000000;">password</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; username: config.<span style="color: #000000;">username</span>, url: config.<span style="color: #000000;">url</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span></p>
<p>&nbsp; &nbsp; &nbsp; _initialized = <span style="color: #000099; font-weight: bold;">true</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span><br />
<span style="color: #000000;">&#125;</span></div>
</div>
</div>
<p></p>
<p>This also requires an override in <code>grails-app/conf/spring/resources.groovy</code>:</p>
<div class="syntax_hilite">
<div id="java-22">
<div class="java"><span style="color: #3333ff;">import com.burtbeckwith.grails.delayds.DelayedDataSource</span><br />
...<br />
<span style="color: #000000;">beans</span> = <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp;...<br />
&nbsp; &nbsp;<span style="color: #000000;">dataSource</span><span style="color: #000000;">&#40;</span>DelayedDataSource<span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;...<br />
<span style="color: #000000;">&#125;</span></div>
</div>
</div>
<p></p>
<p>This creates a <code>BasicDataSource</code> which is what Grails will use by default, but of course feel free to change it to <a target='_blank' href='http://sourceforge.net/projects/c3p0/'>c3p0<img src='/blog/images/pop.gif'/></a> or some other provider.</p>
<hr />
<p>The net effect of using these classes and overridden Spring bean definitions is that both the <code>DataSource</code> and <code>SessionFactory</code> will be lazily initialized on first use. One option might be to have an initialization page that accepts configuration overrides for the database url, username, etc. to allow an admin to start the app and choose the appropriate settings.</p>
<p>The source files shown here are available at <a target='_blank' href='/blog/files/312/DelayedSessionFactoryBean.groovy'>DelayedSessionFactoryBean<img src='/blog/images/pop.gif'/></a> and <a target='_blank' href='/blog/files/312/DelayedDataSource.groovy'>DelayedDataSource<img src='/blog/images/pop.gif'/></a>, and grab <a target='_blank' href='/blog/files/312/resources.groovy'>resources.groovy<img src='/blog/images/pop.gif'/></a> as a sample to merge into your own <code>resources.groovy</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://burtbeckwith.com/blog/?feed=rss2&amp;p=312</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>ACLs in the Grails Spring Security Plugin</title>
		<link>http://burtbeckwith.com/blog/?p=287</link>
		<comments>http://burtbeckwith.com/blog/?p=287#comments</comments>
		<pubDate>Mon, 28 Dec 2009 02:08:09 +0000</pubDate>
		<dc:creator>Burt</dc:creator>
				<category><![CDATA[grails]]></category>
		<category><![CDATA[grailsplugin]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://burtbeckwith.com/blog/?p=287</guid>
		<description><![CDATA[It has taken way too long, but the Grails Spring Security plugin finally has ACL support. It's not officially available yet, but people have offered to beta test an early version of the plugin with ACLs, so you can download that here and report any issues back. Once it's stable I'll do an official release.
History
Stephan [...]]]></description>
			<content:encoded><![CDATA[<p>It has taken way too long, but the <a target='_blank' href='http://grails.org/'>Grails<img src='/blog/images/pop.gif'/></a> <a target='_blank' href='http://grails.org/plugin/acegi/'>Spring Security plugin<img src='/blog/images/pop.gif'/></a> finally has ACL support. It's not officially available yet, but people have offered to beta test an early version of the plugin with ACLs, so you can download that here and report any issues back. Once it's stable I'll do an official release.</p>
<h1 class='sectionNameH1'>History</h1>
<p>Stephan February did the <a target='_blank' href='http://blog.bruary.net/2008/04/grails-acegi-acl-howto.html'>first work<img src='/blog/images/pop.gif'/></a> adding ACL support to the plugin. Unfortunately at the time the plugin was based on Acegi 1.0.x and I had just converted it to use Spring Security 2.0. No one did the work to convert the ACL support to the new package layout and approach, so this wasn't used.</p>
<p>This is a frequently requested feature, so I created a <a target='_blank' href='http://jira.codehaus.org/browse/GRAILSPLUGINS-723'>feature request<img src='/blog/images/pop.gif'/></a> as a TODO item for myself. I found some time to work on this over the summer and created an initial GORM-based implementation (the standard Spring Security implementation uses JDBC). I was fortunate to be able to use this at a client project at <a target='_blank' href='http://innocentive.com/'>InnoCentive<img src='/blog/images/pop.gif'/></a> which helped to flesh out the ideas and identify a few issues.</p>
<p>Around the same time, Phillip Merensky <a target='_blank' href='http://old.nabble.com/Acegi-Plugin-0.5.1-with-ACL-support-implemented-td24864294.html'>mentioned<img src='/blog/images/pop.gif'/></a> on the mailing list that he was working on an implementation. He wrote about his approach <a target='_blank' href='http://imagesiteproject.wordpress.com/2009/09/24/integration-of-spring-security-into-grails-plugin-approach-3/'>here<img src='/blog/images/pop.gif'/></a> and attached his version of the plugin to the JIRA issue. Phillip's work was very helpful; I've merged his version with mine for the current implementation.</p>
<p>Working with ACLs in Spring Security is complex but it will be easier to understand with a sample application.</p>
<h1 class='sectionNameH1'>Test Application</h1>
<p>Create a test application</p>
<div class='console'>
grails create-app acltest<br />
cd acltest
</div>
<p>Download the plugin with ACL support <a target='_blank' href='/blog/files/287/grails-acegi-0.5.2-ACL.zip'>here<img src='/blog/images/pop.gif'/></a> and install it:</p>
<div class='console'>
grails install-plugin /path/to/grails-acegi-0.5.2-ACL.zip
</div>
<p>As with any application using the plugin, you need to run the <code>create-auth-domains</code> script, plus <code>generate-manager</code> if you want the generated GSPs and <code>generate-registration</code> if you want basic registration support:</p>
<div class='console'>
grails create-auth-domains acltest.User acltest.Role acltest.Requestmap<br />
grails generate-manager<br />
grails generate-registration
</div>
<p>The ACL support uses domain classes but to allow customizing the domain classes (e.g. to enable Hibernate 2<sup>nd</sup>-level caching) there's a script that copies the domain classes into your application:</p>
<div class='console'>
grails create-acl-domains
</div>
<p>The script takes no parameters since the package and names aren't configurable - the plugin code imports the domain classes.</p>
<p>Next, switch from using <code>Requestmap</code> entries in the database to using annotated controllers:</p>
<ul>
<li>delete <code>grails-app/domain/acltest/Requestmap.groovy</code></li>
<li>delete <code>grails-app/controllers/RequestmapController.groovy</code></li>
<li>delete the <code>grails-app/views/requestmap</code> directory and its GSPs</li>
<li>delete <code>Requestmap</code> import from <code>grails-app/controllers/RoleController.groovy</code></li>
<li>in <code>grails-app/conf/SecurityConfig.groovy</code>, disable requestmaps (<code>useRequestMapDomainClass = false</code>) and enable annotations (<code>useControllerAnnotations = true</code>), and remove the <code>requestMapClass</code> property:
<div class="syntax_hilite">
<div id="java-34">
<div class="java">security <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp;active = <span style="color: #000099; font-weight: bold;">true</span></p>
<p>&nbsp; &nbsp;loginUserDomainClass = <span style="color: #0000ff;">'acltest.User'</span><br />
&nbsp; &nbsp;authorityDomainClass = <span style="color: #0000ff;">'acltest.Role'</span></p>
<p>&nbsp; &nbsp;useRequestMapDomainClass = <span style="color: #000099; font-weight: bold;">false</span><br />
&nbsp; &nbsp;useControllerAnnotations = <span style="color: #000099; font-weight: bold;">true</span><br />
<span style="color: #000000;">&#125;</span></div>
</div>
</div>
<p>
</li>
</ul>
<p>To enable ACL processing, set the <code>useAcl</code> attribute to <code>true</code>:</p>
<div class="syntax_hilite">
<div id="java-35">
<div class="java">security <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp;active = <span style="color: #000099; font-weight: bold;">true</span></p>
<p>&nbsp; &nbsp;loginUserDomainClass = <span style="color: #0000ff;">'acltest.User'</span><br />
&nbsp; &nbsp;authorityDomainClass = <span style="color: #0000ff;">'acltest.Role'</span></p>
<p>&nbsp; &nbsp;useRequestMapDomainClass = <span style="color: #000099; font-weight: bold;">false</span><br />
&nbsp; &nbsp;useControllerAnnotations = <span style="color: #000099; font-weight: bold;">true</span></p>
<p>&nbsp; &nbsp;useAcl = <span style="color: #000099; font-weight: bold;">true</span><br />
<span style="color: #000000;">&#125;</span></div>
</div>
</div>
<p></p>
<p>We'll need a domain class to test with, so create a <code>Report</code> domain class:</p>
<div class='console'>
grails create-domain-class acltest.Report
</div>
<p>and add a <code>name</code> property for testing:</p>
<div class="syntax_hilite">
<div id="java-36">
<div class="java">package acltest</p>
<p><span style="color: #000099; font-weight: bold;">class</span> Report <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp;<a href="http://www.google.com/search?q=allinurl%3AString+java.sun.com&amp;bntl=1"><span style="color: #000000;">String</span></a> name<br />
<span style="color: #000000;">&#125;</span></div>
</div>
</div>
<p></p>
<h1 class='sectionNameH1'>Working with ACLs</h1>
<p>Probably the most important interface for ACLs is <a target='_blank' href='http://static.springsource.org/spring-security/site/apidocs/org/springframework/security/acls/Permission.html'>Permission<img src='/blog/images/pop.gif'/></a>. You can implement the interface yourself, but <a target='_blank' href='http://static.springsource.org/spring-security/site/apidocs/org/springframework/security/acls/domain/BasePermission.html'>BasePermission<img src='/blog/images/pop.gif'/></a> has <code>READ</code>, <code>WRITE</code>, <code>CREATE</code>, <code>DELETE</code>, and <code>ADMINISTRATION</code> instances that should be sufficient for your needs.</p>
<p>The plugin provides a new service, <code>AclUtilService</code>, to grant and revoke permissions, and to check if permissions are granted. The service methods are:</p>
<ul>
<li>
<code>void addPermission(object, recipient, Permission permission)</code> grants the specified permission to the recipient (either the login name or an <code>Authentication</code>) for the specified instance
</li>
<li>
<code>void addPermission(Class< ?> domainClass, long id, recipient, Permission permission)</code> grants the specified permission to the recipient (either the login name or an <code>Authentication</code>) for the specified instance; use this overload to avoid loading the instance
</li>
<li>
<code>void deletePermission(object, recipient, Permission permission)</code> removes the grant of the specified permission from the recipient (either the login name or an <code>Authentication</code>) for the specified instance
</li>
<li>
<code>void deletePermission(Class< ?> domainClass, long id, recipient, Permission permission)</code> removes the grant of the specified permission from the recipient (either the login name or an <code>Authentication</code>) for the specified instance; use this overload to avoid loading the instance
</li>
<li>
<code>boolean hasPermission(Authentication authentication, domainObject, Permission permission)</code> checks if the authentication has a grant of the specified permission for the specified instance
</li>
<li>
<code>boolean hasPermission(Authentication authentication, domainObject, Permission[] permissions)</code> checks if the authentication has a grant of any of the specified permissions for the specified instance; the first one that is found is used, so the order of the array matters
</li>
</ul>
<p>Creating, editing, or deleting permissions requires an authenticated user. The default required role is <code>ROLE_ADMIN</code> for all actions, but this can be configured in <code>SecurityConfig.groovy</code>. Change the <code>acl.authority.changeOwnership</code> property to change who can call <code>OwnershipAcl.setOwner()</code>. Change the <code>acl.authority.modifyAuditingDetails</code> property to change who can call <code>AuditableAcl.updateAuditing()</code>. And change <code>acl.authority.changeAclDetails</code> to change who can call <code>MutableAcl.deleteAce()</code>, <code>MutableAcl.insertAce()</code>, <code>MutableAcl.setEntriesInheriting()</code>, <code>MutableAcl.setParent()</code>, or <code>MutableAcl.updateAce()</code>.</p>
<p>You'll probably want to create an admin UI that uses <code>AclUtilService</code> and is aware of your secured domain classes and business rules.</p>
<h1 class='sectionNameH1'>Configuration</h1>
<p>Configuring ACL support happens in two places; you configure Voters that have one or more associated permissions and a domain class (which can be an abstract base class), and you configure which service methods use which voters. Often there will be a 1-1 relationship between these but since they're separate, you can re-use the voters for multiple service methods. And you may not even need custom voters; if you only want to secure methods with roles, or if you only need return value checking, then you wouldn't configure any voters, but you'd still configure method restrictions.</p>
<p>There are two types of ACL checks; method return value and method parameter. The plugin creates two voters for return value checks, one for single values (<code>AFTER_ACL_READ</code>) and one for collections (<code>AFTER_ACL_COLLECTION_READ</code>). Each requires that the authenticated user have <code>BasePermission.READ</code>. An optimization would be to allow access to admins (who have been granted BasePermission.ADMINISTRATION); to configure this, redefine the beans in <code>grails-app/conf/spring/resources.groovy</code>:</p>
<div class="syntax_hilite">
<div id="java-37">
<div class="java">beans = <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp;afterAclCollectionRead<span style="color: #000000;">&#40;</span>AclEntryAfterInvocationCollectionFilteringProvider,<br />
&nbsp; &nbsp; &nbsp; &nbsp; ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'aclService'</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#91;</span>BasePermission.<span style="color: #000000;">READ</span>, BasePermission.<span style="color: #000000;">ADMINISTRATION</span><span style="color: #000000;">&#93;</span><span style="color: #000000;">&#41;</span></p>
<p>&nbsp; &nbsp;afterAclRead<span style="color: #000000;">&#40;</span>AclEntryAfterInvocationProvider,<br />
&nbsp; &nbsp; &nbsp; &nbsp; ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'aclService'</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#91;</span>BasePermission.<span style="color: #000000;">READ</span>, BasePermission.<span style="color: #000000;">ADMINISTRATION</span><span style="color: #000000;">&#93;</span><span style="color: #000000;">&#41;</span><br />
<span style="color: #000000;">&#125;</span></div>
</div>
</div>
<p></p>
<p>Voters for method parameter checks (the first parameter of the specified type or a subclass is checked) can be configured either in <code>SecurityConfig.groovy</code> or in domain class annotations. Putting the configuration in <code>SecurityConfig.groovy</code> keeps everything in one place, whereas the annotations let you put the declarations where they apply, so they're self-documenting. Use whichever approach you prefer.</p>
<p>To configure them in <code>SecurityConfig.groovy</code>, use the <code>acl.voters</code> property, e.g.</p>
<div class="syntax_hilite">
<div id="java-38">
<div class="java"><span style="color: #3333ff;">import org.springframework.security.acls.domain.BasePermission</span><br />
<span style="color: #3333ff;">import acltest.Report</span></p>
<p>security <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp;...<br />
&nbsp; &nbsp;<span style="color: #000000;">useAcl</span> = <span style="color: #000099; font-weight: bold;">true</span></p>
<p>&nbsp; &nbsp;acl.<span style="color: #000000;">voters</span> = <span style="color: #000000;">&#91;</span></p>
<p>&nbsp; &nbsp; &nbsp; aclReportWriteVoter: <span style="color: #000000;">&#91;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; configAttribute: <span style="color: #0000ff;">'ACL_REPORT_WRITE'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; permissions: <span style="color: #000000;">&#91;</span>BasePermission.<span style="color: #000000;">ADMINISTRATION</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; BasePermission.<span style="color: #000000;">WRITE</span><span style="color: #000000;">&#93;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; domainObjectClass: Report<span style="color: #000000;">&#93;</span>,<br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; aclReportDeleteVoter: <span style="color: #000000;">&#91;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; configAttribute: <span style="color: #0000ff;">'ACL_REPORT_DELETE'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; permissions: <span style="color: #000000;">&#91;</span>BasePermission.<span style="color: #000000;">ADMINISTRATION</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; BasePermission.<span style="color: #000000;">DELETE</span><span style="color: #000000;">&#93;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; domainObjectClass: Report<span style="color: #000000;">&#93;</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#93;</span><br />
<span style="color: #000000;">&#125;</span></div>
</div>
</div>
<p></p>
<p>which creates a 'write' voter and a 'delete' voter. The equivalent annotations would be:</p>
<div class="syntax_hilite">
<div id="java-39">
<div class="java">package acltest</p>
<p><span style="color: #3333ff;">import org.codehaus.groovy.grails.plugins.springsecurity.acl.AclVoter</span><br />
<span style="color: #3333ff;">import org.codehaus.groovy.grails.plugins.springsecurity.acl.AclVoters</span></p>
<p>@AclVoters<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#91;</span><br />
&nbsp; &nbsp;@AclVoter<span style="color: #000000;">&#40;</span>name=<span style="color: #0000ff;">'aclReportWriteVoter'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;configAttribute=<span style="color: #0000ff;">'ACL_REPORT_WRITE'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;permissions=<span style="color: #000000;">&#91;</span><span style="color: #0000ff;">'ADMINISTRATION'</span>, <span style="color: #0000ff;">'WRITE'</span><span style="color: #000000;">&#93;</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp;@AclVoter<span style="color: #000000;">&#40;</span>name=<span style="color: #0000ff;">'aclReportDeleteVoter'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;configAttribute=<span style="color: #0000ff;">'ACL_REPORT_DELETE'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;permissions=<span style="color: #000000;">&#91;</span><span style="color: #0000ff;">'ADMINISTRATION'</span>, <span style="color: #0000ff;">'DELETE'</span><span style="color: #000000;">&#93;</span><span style="color: #000000;">&#41;</span><br />
<span style="color: #000000;">&#93;</span><span style="color: #000000;">&#41;</span><br />
<span style="color: #000099; font-weight: bold;">class</span> Report <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp;<a href="http://www.google.com/search?q=allinurl%3AString+java.sun.com&amp;bntl=1"><span style="color: #000000;">String</span></a> name<br />
<span style="color: #000000;">&#125;</span></div>
</div>
</div>
<p></p>
<p>Note that since you cannot use an annotation more than once, in a case like this where there can be multiple voter annotations for a domain class they need to be defined as attributes of a containing annotation (<code>AclVoters</code>). If you only have a single voter then you can annotate the class with that and omit the containing annotation.</p>
<p>The voter configuration should be fairly clear; there's a <code>name</code> parameter that's used as the Spring bean name (so it must be unique), a <code>configAttribute</code> parameter that's arbitrary but typically uses a naming convention where it starts with 'ACL_',  and one or more permissions. The one limitation of annotations over the static configuration is that annotations cannot have <code>Permission</code>s as parameters, so <code>String</code>s are used instead. This limits you to naming fields of the <a target='_blank' href='http://static.springsource.org/spring-security/site/apidocs/org/springframework/security/acls/domain/BasePermission.html'>BasePermission<img src='/blog/images/pop.gif'/></a> class. If you have custom permission classes you'll need to use the static configuration.</p>
<h1 class='sectionNameH1'>Securing Service Methods</h1>
<p>As with voters, there are two ways to define the access rules for service methods. You can define a static <code>springSecurityACL</code> property with configuration options, or annotate the class and/or individual methods.</p>
<p>Let's create a service to test ACLs:</p>
<div class='console'>
grails create-service acltest.Report
</div>
<p>and add some methods that work with <code>Report</code>s:</p>
<div class="syntax_hilite">
<div id="java-40">
<div class="java">package acltest</p>
<p><span style="color: #000099; font-weight: bold;">class</span> ReportService <span style="color: #000000;">&#123;</span></p>
<p>&nbsp; &nbsp;<span style="color: #0000ff;">boolean</span> transactional = <span style="color: #000099; font-weight: bold;">true</span></p>
<p>&nbsp; &nbsp;Report getReport<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">long</span> id<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; Report.<span style="color: #000000;">get</span><span style="color: #000000;">&#40;</span>id<span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;Report createReport<span style="color: #000000;">&#40;</span>params<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; Report report = <span style="color: #000099; font-weight: bold;">new</span> Report<span style="color: #000000;">&#40;</span>params<span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; report.<span style="color: #000000;">save</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; report<br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;<a href="http://www.google.com/search?q=allinurl%3AList+java.sun.com&amp;bntl=1"><span style="color: #000000;">List</span></a> getAllReports<span style="color: #000000;">&#40;</span>params = <span style="color: #000000;">&#91;</span>:<span style="color: #000000;">&#93;</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span> Report.<span style="color: #000000;">list</span><span style="color: #000000;">&#40;</span>params<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;<a href="http://www.google.com/search?q=allinurl%3AString+java.sun.com&amp;bntl=1"><span style="color: #000000;">String</span></a> getReportName<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">long</span> id<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span> Report.<span style="color: #000000;">get</span><span style="color: #000000;">&#40;</span>id<span style="color: #000000;">&#41;</span>.<span style="color: #000000;">name</span> <span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;Report updateReport<span style="color: #000000;">&#40;</span>Report report, params<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; report.<span style="color: #000000;">properties</span> = params<br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #000000;">&#40;</span>!report.<span style="color: #000000;">hasErrors</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;report.<span style="color: #000000;">save</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; report<br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;<span style="color: #0000ff;">void</span> deleteReport<span style="color: #000000;">&#40;</span>Report report<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; report.<span style="color: #000000;">delete</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span><br />
<span style="color: #000000;">&#125;</span></div>
</div>
</div>
<p></p>
<p>To configure the rules in one place, add a <code>springSecurityACL</code> property:</p>
<div class="syntax_hilite">
<div id="java-41">
<div class="java"><span style="color: #0000ff;">static</span> springSecurityACL = <span style="color: #000000;">&#91;</span><br />
&nbsp; &nbsp;getReportName: <span style="color: #000000;">&#91;</span><span style="color: #0000ff;">'ROLE_USER'</span>, <span style="color: #0000ff;">'ROLE_ADMIN'</span><span style="color: #000000;">&#93;</span>,<br />
&nbsp; &nbsp;getAllReports: <span style="color: #000000;">&#91;</span><span style="color: #0000ff;">'ROLE_USER'</span>, <span style="color: #0000ff;">'AFTER_ACL_COLLECTION_READ'</span><span style="color: #000000;">&#93;</span>,<br />
&nbsp; &nbsp;getReport: <span style="color: #000000;">&#91;</span><span style="color: #0000ff;">'ROLE_USER'</span>, <span style="color: #0000ff;">'AFTER_ACL_READ'</span><span style="color: #000000;">&#93;</span>,<br />
&nbsp; &nbsp;updateReport: <span style="color: #000000;">&#91;</span><span style="color: #0000ff;">'ACL_REPORT_WRITE'</span><span style="color: #000000;">&#93;</span>,<br />
&nbsp; &nbsp;deleteReport: <span style="color: #000000;">&#91;</span><span style="color: #0000ff;">'ACL_REPORT_DELETE'</span><span style="color: #000000;">&#93;</span><br />
<span style="color: #000000;">&#93;</span></div>
</div>
</div>
<p></p>
<p>and the equivalent annotated version would be:</p>
<div class="syntax_hilite">
<div id="java-42">
<div class="java">package acltest</p>
<p><span style="color: #3333ff;">import org.codehaus.groovy.grails.plugins.springsecurity.Secured</span></p>
<p><span style="color: #000099; font-weight: bold;">class</span> ReportService <span style="color: #000000;">&#123;</span></p>
<p>&nbsp; &nbsp;<span style="color: #0000ff;">boolean</span> transactional = <span style="color: #000099; font-weight: bold;">true</span></p>
<p>&nbsp; &nbsp;@Secured<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#91;</span><span style="color: #0000ff;">'ROLE_USER'</span>, <span style="color: #0000ff;">'AFTER_ACL_READ'</span><span style="color: #000000;">&#93;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;Report getReport<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">long</span> id<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; Report.<span style="color: #000000;">get</span><span style="color: #000000;">&#40;</span>id<span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;Report createReport<span style="color: #000000;">&#40;</span>params<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; Report report = <span style="color: #000099; font-weight: bold;">new</span> Report<span style="color: #000000;">&#40;</span>params<span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; report.<span style="color: #000000;">save</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; report<br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;@Secured<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#91;</span><span style="color: #0000ff;">'ROLE_USER'</span>, <span style="color: #0000ff;">'AFTER_ACL_COLLECTION_READ'</span><span style="color: #000000;">&#93;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;<a href="http://www.google.com/search?q=allinurl%3AList+java.sun.com&amp;bntl=1"><span style="color: #000000;">List</span></a> getAllReports<span style="color: #000000;">&#40;</span>params = <span style="color: #000000;">&#91;</span>:<span style="color: #000000;">&#93;</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span> Report.<span style="color: #000000;">list</span><span style="color: #000000;">&#40;</span>params<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;@Secured<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#91;</span><span style="color: #0000ff;">'ROLE_USER'</span>, <span style="color: #0000ff;">'ROLE_ADMIN'</span><span style="color: #000000;">&#93;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;<a href="http://www.google.com/search?q=allinurl%3AString+java.sun.com&amp;bntl=1"><span style="color: #000000;">String</span></a> getReportName<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">long</span> id<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span> Report.<span style="color: #000000;">get</span><span style="color: #000000;">&#40;</span>id<span style="color: #000000;">&#41;</span>.<span style="color: #000000;">name</span> <span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;@Secured<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#91;</span><span style="color: #0000ff;">'ACL_REPORT_WRITE'</span><span style="color: #000000;">&#93;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;Report updateReport<span style="color: #000000;">&#40;</span>Report report, params<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; report.<span style="color: #000000;">properties</span> = params<br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #000000;">&#40;</span>!report.<span style="color: #000000;">hasErrors</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;report.<span style="color: #000000;">save</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; report<br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;@Secured<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#91;</span><span style="color: #0000ff;">'ACL_REPORT_DELETE'</span><span style="color: #000000;">&#93;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;<span style="color: #0000ff;">void</span> deleteReport<span style="color: #000000;">&#40;</span>Report report<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; report.<span style="color: #000000;">delete</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span><br />
<span style="color: #000000;">&#125;</span></div>
</div>
</div>
<p></p>
<p>The configuration specifies these rules:</p>
<ul>
<li>
<code>getReportName</code> requires that the authenticated user have either <code>ROLE_USER</code> or <code>ROLE_ADMIN</code> (but no ACL rules)</li>
<li>
<code>getAllReports</code> requires <code>ROLE_USER</code> and will have elements removed from the returned <code>List</code> that the user doesn't have an ACL grant for (thanks to <code>AFTER_ACL_COLLECTION_READ</code>); the user must have one of the permissions defined in the <code>afterAclCollectionRead</code> bean (by default <code>BasePermission.READ</code>) for each element in the list; elements that don't have access granted will be removed
</li>
<li>
<code>getReport</code> requires <code>ROLE_USER</code> and will be denied (thanks to <code>AFTER_ACL_READ</code>) unless the user has one of the permissions defined in the <code>afterAclRead</code> bean (by default <code>BasePermission.READ</code>).
</li>
<li>
<code>updateReport</code> has no role restrictions but must satisfy the requirements of the <code>aclReportWriteVoter</code> voter (which has the <code>ACL_REPORT_WRITE</code> config attribute), i.e. <code>BasePermission.ADMINISTRATION</code> or <code>BasePermission.WRITE</code>
</li>
<li>
<code>deleteReport</code> has no role restrictions but must satisfy the requirements of the <code>aclReportDeleteVoter</code> voter (which has the <code>ACL_REPORT_DELETE</code> config attribute), i.e. <code>BasePermission.ADMINISTRATION</code> or <code>BasePermission.DELETE</code>
</li>
<li>
<code>createReport</code> has no restrictions
</li>
</ul>
<p>To test this out we'll need some users; create those and their grants in BootStrap.groovy:</p>
<div class="syntax_hilite">
<div id="java-43">
<div class="java"><span style="color: #3333ff;">import org.springframework.security.GrantedAuthority</span><br />
<span style="color: #3333ff;">import org.springframework.security.GrantedAuthorityImpl</span><br />
<span style="color: #3333ff;">import org.springframework.security.acls.domain.BasePermission</span><br />
<span style="color: #3333ff;">import org.springframework.security.context.SecurityContextHolder as SCH</span><br />
<span style="color: #3333ff;">import org.springframework.security.providers.UsernamePasswordAuthenticationToken</span></p>
<p><span style="color: #3333ff;">import acltest.Report</span><br />
<span style="color: #3333ff;">import acltest.Role</span><br />
<span style="color: #3333ff;">import acltest.User</span></p>
<p><span style="color: #000099; font-weight: bold;">class</span> BootStrap <span style="color: #000000;">&#123;</span></p>
<p>&nbsp; &nbsp;def aclUtilService<br />
&nbsp; &nbsp;def passwordEncoder<br />
&nbsp; &nbsp;def sessionFactory</p>
<p>&nbsp; &nbsp;def init = <span style="color: #000000;">&#123;</span> servletContext -&gt;<br />
&nbsp; &nbsp; &nbsp; createUsers<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; createReports<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; createGrants<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span></p>
<p>&nbsp; &nbsp; &nbsp; sessionFactory.<span style="color: #000000;">currentSession</span>.<span style="color: #000000;">flush</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;<span style="color: #000099; font-weight: bold;">private</span> <span style="color: #0000ff;">void</span> createUsers<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; def adminRole = <span style="color: #000099; font-weight: bold;">new</span> Role<span style="color: #000000;">&#40;</span>description: <span style="color: #0000ff;">'Admin'</span>, authority: <span style="color: #0000ff;">'ROLE_ADMIN'</span><span style="color: #000000;">&#41;</span>.<span style="color: #000000;">save</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; def admin = <span style="color: #000099; font-weight: bold;">new</span> User<span style="color: #000000;">&#40;</span>username: <span style="color: #0000ff;">'admin'</span>, userRealName: <span style="color: #0000ff;">'admin'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; passwd: passwordEncoder.<span style="color: #000000;">encodePassword</span><span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'admin'</span>, <span style="color: #000099; font-weight: bold;">null</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; enabled: <span style="color: #000099; font-weight: bold;">true</span>, email: <span style="color: #0000ff;">'admin@admin.com'</span><span style="color: #000000;">&#41;</span>.<span style="color: #000000;">save</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; adminRole.<span style="color: #000000;">addToPeople</span> admin</p>
<p>&nbsp; &nbsp; &nbsp; def userRole = <span style="color: #000099; font-weight: bold;">new</span> Role<span style="color: #000000;">&#40;</span>description: <span style="color: #0000ff;">'User'</span>, authority: <span style="color: #0000ff;">'ROLE_USER'</span><span style="color: #000000;">&#41;</span>.<span style="color: #000000;">save</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; def user1 = <span style="color: #000099; font-weight: bold;">new</span> User<span style="color: #000000;">&#40;</span>username: <span style="color: #0000ff;">'user1'</span>, userRealName: <span style="color: #0000ff;">'user1'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; passwd: passwordEncoder.<span style="color: #000000;">encodePassword</span><span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'user1'</span>, <span style="color: #000099; font-weight: bold;">null</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; enabled: <span style="color: #000099; font-weight: bold;">true</span>, email: <span style="color: #0000ff;">'user1@user.com'</span><span style="color: #000000;">&#41;</span>.<span style="color: #000000;">save</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; userRole.<span style="color: #000000;">addToPeople</span> user1</p>
<p>&nbsp; &nbsp; &nbsp; def user2 = <span style="color: #000099; font-weight: bold;">new</span> User<span style="color: #000000;">&#40;</span>username: <span style="color: #0000ff;">'user2'</span>, userRealName: <span style="color: #0000ff;">'user2'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; passwd: passwordEncoder.<span style="color: #000000;">encodePassword</span><span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'user2'</span>, <span style="color: #000099; font-weight: bold;">null</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; enabled: <span style="color: #000099; font-weight: bold;">true</span>, email: <span style="color: #0000ff;">'user2@user.com'</span><span style="color: #000000;">&#41;</span>.<span style="color: #000000;">save</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; userRole.<span style="color: #000000;">addToPeople</span> user2<br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;<span style="color: #000099; font-weight: bold;">private</span> <span style="color: #0000ff;">void</span> createReports<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#40;</span><span style="color: #000000;">1</span>..<span style="color: #000000;">10</span><span style="color: #000000;">&#41;</span>.<span style="color: #000000;">each</span> <span style="color: #000000;">&#123;</span> <span style="color: #000099; font-weight: bold;">new</span> Report<span style="color: #000000;">&#40;</span>name: <span style="color: #0000ff;">"report $it"</span><span style="color: #000000;">&#41;</span>.<span style="color: #000000;">save</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#125;</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;<span style="color: #000099; font-weight: bold;">private</span> <span style="color: #0000ff;">void</span> createGrants<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span></p>
<p>&nbsp; &nbsp; &nbsp; loginAsAdmin<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span></p>
<p>&nbsp; &nbsp; &nbsp; <span style="color: #000099; font-weight: bold;">try</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #116611; font-style: italic;">// user1 can see reports 1-4</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;def user = User.<span style="color: #000000;">findByUsername</span><span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'user1'</span><span style="color: #000000;">&#41;</span>&nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #000000;">&#40;</span><span style="color: #000000;">1</span>..<span style="color: #000000;">4</span><span style="color: #000000;">&#41;</span>.<span style="color: #000000;">each</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; def report = Report.<span style="color: #000000;">findByName</span><span style="color: #000000;">&#40;</span><span style="color: #0000ff;">"report $it"</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; aclUtilService.<span style="color: #000000;">addPermission</span><span style="color: #000000;">&#40;</span>report,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; user.<span style="color: #000000;">username</span>, BasePermission.<span style="color: #000000;">READ</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #000000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #116611; font-style: italic;">// and can edit #3</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;aclUtilService.<span style="color: #000000;">addPermission</span><span style="color: #000000;">&#40;</span>Report.<span style="color: #000000;">findByName</span><span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'report 3'</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;user.<span style="color: #000000;">username</span>, BasePermission.<span style="color: #000000;">WRITE</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #116611; font-style: italic;">// and edit and delete #4</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;aclUtilService.<span style="color: #000000;">addPermission</span><span style="color: #000000;">&#40;</span>Report.<span style="color: #000000;">findByName</span><span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'report 4'</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;user.<span style="color: #000000;">username</span>, BasePermission.<span style="color: #000000;">WRITE</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;aclUtilService.<span style="color: #000000;">addPermission</span><span style="color: #000000;">&#40;</span>Report.<span style="color: #000000;">findByName</span><span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'report 4'</span><span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;user.<span style="color: #000000;">username</span>, BasePermission.<span style="color: #000000;">DELETE</span><span style="color: #000000;">&#41;</span></p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #116611; font-style: italic;">// user2 can see reports 5, 10</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;user = User.<span style="color: #000000;">findByUsername</span><span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'user2'</span><span style="color: #000000;">&#41;</span>&nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #000000;">&#91;</span><span style="color: #000000;">5</span>, <span style="color: #000000;">10</span><span style="color: #000000;">&#93;</span>.<span style="color: #000000;">each</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; def report = Report.<span style="color: #000000;">findByName</span><span style="color: #000000;">&#40;</span><span style="color: #0000ff;">"report $it"</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; aclUtilService.<span style="color: #000000;">addPermission</span><span style="color: #000000;">&#40;</span>report,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; user.<span style="color: #000000;">username</span>, BasePermission.<span style="color: #000000;">READ</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #000000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000099; font-weight: bold;">finally</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;SCH.<span style="color: #000000;">clearContext</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;<span style="color: #116611; font-style: italic;">// have to be authenticated as an admin to create ACLs</span><br />
&nbsp; &nbsp;<span style="color: #000099; font-weight: bold;">private</span> <span style="color: #0000ff;">void</span> loginAsAdmin<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; SCH.<span style="color: #000000;">context</span>.<span style="color: #000000;">authentication</span> = <span style="color: #000099; font-weight: bold;">new</span> UsernamePasswordAuthenticationToken<span style="color: #000000;">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">'admin'</span>, <span style="color: #0000ff;">'password'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#91;</span><span style="color: #000099; font-weight: bold;">new</span> GrantedAuthorityImpl<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'ROLE_ADMIN'</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#93;</span> as GrantedAuthority<span style="color: #000000;">&#91;</span><span style="color: #000000;">&#93;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;def destroy = <span style="color: #000000;">&#123;</span><span style="color: #000000;">&#125;</span><br />
<span style="color: #000000;">&#125;</span></div>
</div>
</div>
<p></p>
<p>And to have a UI to test with, let's create a <code>Report</code> controller and GSPs:</p>
<div class='console'>
grails generate-all acltest.Report
</div>
<p>But to use the controller, it will have to be reworked to use <code>ReportService</code>. It's a good idea to put all create/edit/delete code in a transactional service, but in this case we need to move all database access to the service to ensure that appropriate access checks are made:</p>
<div class="syntax_hilite">
<div id="java-44">
<div class="java">package acltest</p>
<p><span style="color: #3333ff;">import org.codehaus.groovy.grails.plugins.springsecurity.Secured</span></p>
<p><span style="color: #3333ff;">import org.springframework.dao.DataIntegrityViolationException</span></p>
<p>@Secured<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#91;</span><span style="color: #0000ff;">'ROLE_ADMIN'</span>, <span style="color: #0000ff;">'ROLE_USER'</span><span style="color: #000000;">&#93;</span><span style="color: #000000;">&#41;</span><br />
<span style="color: #000099; font-weight: bold;">class</span> ReportController <span style="color: #000000;">&#123;</span></p>
<p>&nbsp; &nbsp;<span style="color: #0000ff;">static</span> allowedMethods = <span style="color: #000000;">&#91;</span>delete: <span style="color: #0000ff;">'POST'</span>, save: <span style="color: #0000ff;">'POST'</span>, update: <span style="color: #0000ff;">'POST'</span><span style="color: #000000;">&#93;</span></p>
<p>&nbsp; &nbsp;<span style="color: #0000ff;">static</span> defaultAction = <span style="color: #0000ff;">'list'</span></p>
<p>&nbsp; &nbsp;def reportService</p>
<p>&nbsp; &nbsp;def list = <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; params.<span style="color: #000000;">max</span> = <a href="http://www.google.com/search?q=allinurl%3AMath+java.sun.com&amp;bntl=1"><span style="color: #000000;">Math</span></a>.<span style="color: #000000;">min</span><span style="color: #000000;">&#40;</span>params.<span style="color: #000000;">max</span> ? params.<span style="color: #000000;">max</span>.<span style="color: #000000;">toInteger</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span> : <span style="color: #000000;">10</span>, <span style="color: #000000;">100</span><span style="color: #000000;">&#41;</span></p>
<p>&nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#91;</span>reportInstanceList: reportService.<span style="color: #000000;">getAllReports</span><span style="color: #000000;">&#40;</span>params<span style="color: #000000;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp;reportInstanceTotal: Report.<span style="color: #000000;">count</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#93;</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;def show = <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; def reportInstance = reportService.<span style="color: #000000;">getReport</span><span style="color: #000000;">&#40;</span>params.<span style="color: #000000;">id</span>?.<span style="color: #000000;">toLong</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #000000;">&#40;</span>!reportInstance<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;flash.<span style="color: #000000;">message</span> = <span style="color: #0000ff;">"Report not found with id $params.id"</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;redirect action: list<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #990000;">return</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#91;</span>reportInstance: reportInstance<span style="color: #000000;">&#93;</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;def delete = <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; def reportInstance = reportService.<span style="color: #000000;">getReport</span><span style="color: #000000;">&#40;</span>params.<span style="color: #000000;">id</span>?.<span style="color: #000000;">toLong</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #000000;">&#40;</span>!reportInstance<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;flash.<span style="color: #000000;">message</span> = <span style="color: #0000ff;">"Report not found with id $params.id"</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;redirect action: list<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #990000;">return</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; <span style="color: #000099; font-weight: bold;">try</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;reportService.<span style="color: #000000;">deleteReport</span><span style="color: #000000;">&#40;</span>reportInstance<span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;flash.<span style="color: #000000;">message</span> = <span style="color: #0000ff;">"Report $params.id deleted"</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;redirect action: list<br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000099; font-weight: bold;">catch</span> <span style="color: #000000;">&#40;</span>DataIntegrityViolationException e<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;flash.<span style="color: #000000;">message</span> = <span style="color: #0000ff;">"Report $params.id could not be deleted"</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;redirect action: show, id: params.<span style="color: #000000;">id</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;def edit = <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; def reportInstance = reportService.<span style="color: #000000;">getReport</span><span style="color: #000000;">&#40;</span>params.<span style="color: #000000;">id</span>?.<span style="color: #000000;">toLong</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #000000;">&#40;</span>!reportInstance<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;flash.<span style="color: #000000;">message</span> = <span style="color: #0000ff;">"Report not found with id $params.id"</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;redirect action: list<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #990000;">return</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#91;</span>reportInstance: reportInstance<span style="color: #000000;">&#93;</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;def update = <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; def reportInstance = reportService.<span style="color: #000000;">getReport</span><span style="color: #000000;">&#40;</span>params.<span style="color: #000000;">id</span>?.<span style="color: #000000;">toLong</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #000000;">&#40;</span>!reportInstance<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;flash.<span style="color: #000000;">message</span> = <span style="color: #0000ff;">"Report not found with id $params.id"</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;redirect action: list<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #990000;">return</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #000000;">&#40;</span>params.<span style="color: #000000;">version</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">long</span> version = params.<span style="color: #000000;">version</span>.<span style="color: #000000;">toLong</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">if</span> <span style="color: #000000;">&#40;</span>reportInstance.<span style="color: #000000;">version</span>&gt; version<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; reportInstance.<span style="color: #000000;">errors</span>.<span style="color: #000000;">rejectValue</span><span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'version'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">'report.optimistic.locking.failure'</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #0000ff;">'Another user has updated this Report while you were editing.'</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; render view:<span style="color: #0000ff;">'edit'</span>,model: <span style="color: #000000;">&#91;</span>reportInstance: reportInstance<span style="color: #000000;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #990000;">return</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #000000;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; reportService.<span style="color: #000000;">updateReport</span><span style="color: #000000;">&#40;</span>reportInstance, params<span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #000000;">&#40;</span>reportInstance.<span style="color: #000000;">hasErrors</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;render view: <span style="color: #0000ff;">'edit'</span>, model: <span style="color: #000000;">&#91;</span>reportInstance: reportInstance<span style="color: #000000;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #990000;">return</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; flash.<span style="color: #000000;">message</span> = <span style="color: #0000ff;">"Report $params.id updated"</span><br />
&nbsp; &nbsp; &nbsp; redirect action: show, id: reportInstance.<span style="color: #000000;">id</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;def create = <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#91;</span>reportInstance: <span style="color: #000099; font-weight: bold;">new</span> Report<span style="color: #000000;">&#40;</span>params<span style="color: #000000;">&#41;</span><span style="color: #000000;">&#93;</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;def save = <span style="color: #000000;">&#123;</span></p>
<p>&nbsp; &nbsp; &nbsp; def reportInstance = reportService.<span style="color: #000000;">createReport</span><span style="color: #000000;">&#40;</span>params<span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #0000ff;">if</span> <span style="color: #000000;">&#40;</span>reportInstance.<span style="color: #000000;">hasErrors</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;render view: <span style="color: #0000ff;">'create'</span>, model: <span style="color: #000000;">&#91;</span>reportInstance: reportInstance<span style="color: #000000;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="color: #990000;">return</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp; &nbsp; flash.<span style="color: #000000;">message</span> = <span style="color: #0000ff;">"Report $reportInstance.id created"</span><br />
&nbsp; &nbsp; &nbsp; redirect action: show, id: reportInstance.<span style="color: #000000;">id</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span><br />
<span style="color: #000000;">&#125;</span></div>
</div>
</div>
<p></p>
<p>Note that the controller is annotated to require either <code>ROLE_USER</code> or <code>ROLE_ADMIN</code>. Since services have nothing to do with HTTP, when access is blocked you cannot be redirected to the login page as when you try to access a URL that requires an authentication. So you need to configure URLs with similar role requirements to give the user a chance to attempt a login before calling secured service methods.</p>
<hr />
<p>Start the app:</p>
<div class='console'>
grails run-app
</div>
<p>and open <a target='_blank' href='http://localhost:8080/acltest/report/list'>http://localhost:8080/acltest/report/list<img src='/blog/images/pop.gif'/></a></p>
<p>Login as user2/user2 and you should only see reports #5 and #10. Logout via <a target='_blank' href='http://localhost:8080/acltest/logout'>http://localhost:8080/acltest/logout<img src='/blog/images/pop.gif'/></a> and open the list page again, this time logging in as user1/user1. Now you should be able to see instances #1-4.</p>
<p>Verify that you can view #3 directly by clicking the id or opening <a target='_blank' href='http://localhost:8080/acltest/report/show/3'>http://localhost:8080/acltest/report/show/3<img src='/blog/images/pop.gif'/></a>. Also verify that you can edit #3 but cannot delete it.</p>
<p>Verify that you can view #4 directly by clicking the id or opening <a target='_blank' href='http://localhost:8080/acltest/report/show/4'>http://localhost:8080/acltest/report/show/4<img src='/blog/images/pop.gif'/></a> and that can edit and delete it.</p>
<p>Verify that you can't view #7 directly by opening <a target='_blank' href='http://localhost:8080/acltest/report/show/7'>http://localhost:8080/acltest/report/show/7<img src='/blog/images/pop.gif'/></a>.</p>
<hr />
<p>You can download the full sample app <a target='_blank' href='/blog/files/287/acltest.tar.gz'>here<img src='/blog/images/pop.gif'/></a> and the plugin with ACL support <a target='_blank' href='/blog/files/287/grails-acegi-0.5.2-ACL.zip'>here<img src='/blog/images/pop.gif'/></a>.</p>
<p>There isn't much documentation available for Spring Security ACLs, but I found <a target='_blank' href='http://server.denksoft.com/wordpress/web-development/spring-security/'>this blog post<img src='/blog/images/pop.gif'/></a> to be very informative and thorough.</p>
<p>If you have questions or issues with the code, please email the <a target='_blank' href='http://grails.org/Mailing+lists'>Grails User mailing list<img src='/blog/images/pop.gif'/></a> so others who might be having similar problems can partipate in the conversation.</p>
]]></content:encoded>
			<wfw:commentRss>http://burtbeckwith.com/blog/?feed=rss2&amp;p=287</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Hierarchical Roles in the Grails Spring Security Plugin</title>
		<link>http://burtbeckwith.com/blog/?p=275</link>
		<comments>http://burtbeckwith.com/blog/?p=275#comments</comments>
		<pubDate>Tue, 22 Dec 2009 02:41:08 +0000</pubDate>
		<dc:creator>Burt</dc:creator>
				<category><![CDATA[grails]]></category>
		<category><![CDATA[grailsplugin]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://burtbeckwith.com/blog/?p=275</guid>
		<description><![CDATA[I was looking at a non-Grails Spring Security application that used hierarchical roles and wondered what it'd take to get this working with the Grails plugin. Turns out it's pretty simple.
Non-hierarchical roles are checked by a RoleVoter but to use hierarchical roles you need a RoleHierarchyVoter. Replacing the roleVoter bean in resources.groovy is all it [...]]]></description>
			<content:encoded><![CDATA[<p>I was looking at a non-<a target='_blank' href='http://grails.org/'>Grails<img src='/blog/images/pop.gif'/></a> Spring Security application that used hierarchical roles and wondered what it'd take to get this working with the Grails plugin. Turns out it's pretty simple.</p>
<p>Non-hierarchical roles are checked by a <a target='_blank' href='http://static.springsource.org/spring-security/site/apidocs/org/springframework/security/vote/RoleVoter.html'>RoleVoter<img src='/blog/images/pop.gif'/></a> but to use hierarchical roles you need a <a target='_blank' href='http://static.springsource.org/spring-security/site/apidocs/org/springframework/security/vote/RoleHierarchyVoter.html'>RoleHierarchyVoter<img src='/blog/images/pop.gif'/></a>. Replacing the <code>roleVoter</code> bean in <code>resources.groovy</code> is all it takes.</p>
<p><code>RoleHierarchyVoter</code> needs an implementation of <a target='_blank' href='http://static.springsource.org/spring-security/site/apidocs/org/springframework/security/userdetails/hierarchicalroles/RoleHierarchy.html'>RoleHierarchy<img src='/blog/images/pop.gif'/></a> and the default implementation in Spring Security is <a target='_blank' href='http://static.springsource.org/spring-security/site/apidocs/org/springframework/security/userdetails/hierarchicalroles/RoleHierarchyImpl.html'>RoleHierarchyImpl<img src='/blog/images/pop.gif'/></a> which parses a String defining the hierarchy. For example, this configuration defines the hierarchy <code>ROLE_SUPERADMIN</code> &gt; <code>ROLE_ADMIN</code> &gt; <code>ROLE_USER</code>:</p>
<div class="syntax_hilite">
<div id="java-47">
<div class="java"><span style="color: #3333ff;">import org.springframework.security.userdetails.hierarchicalroles.RoleHierarchyImpl</span><br />
<span style="color: #3333ff;">import org.springframework.security.vote.RoleHierarchyVoter</span></p>
<p>beans = <span style="color: #000000;">&#123;</span></p>
<p>&nbsp; &nbsp;roleHierarchy<span style="color: #000000;">&#40;</span>RoleHierarchyImpl<span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; hierarchy = <span style="color: #0000ff;">''</span><span style="color: #0000ff;">'<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ROLE_SUPERADMIN &gt; ROLE_ADMIN<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ROLE_ADMIN &gt; ROLE_USER<br />
&nbsp; &nbsp; &nbsp; '</span><span style="color: #0000ff;">''</span><br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;roleVoter<span style="color: #000000;">&#40;</span>RoleHierarchyVoter, ref<span style="color: #000000;">&#40;</span><span style="color: #0000ff;">'roleHierarchy'</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><br />
<span style="color: #000000;">&#125;</span></div>
</div>
</div>
<p></p>
<p>You can download a small demo app <a target='_blank' href='/blog/files/275/hierarchical.tar.gz'>here<img src='/blog/images/pop.gif'/></a> that shows how it works. Unpack the app and run <code>grails run-app</code>, and then open <a target='_blank' href='http://localhost:8080/hierarchical/secure/'>http://localhost:8080/hierarchical/secure/<img src='/blog/images/pop.gif'/></a>. The app creates three users in <code>BootStrap</code>:</p>
<table>
<tr>
<th>Username</th>
<th>Password</th>
<th>Role</th>
</tr>
<tr>
<td>user</td>
<td>user</td>
<td>ROLE_USER</td>
</tr>
<tr>
<td>admin</td>
<td>admin</td>
<td>ROLE_ADMIN</td>
</tr>
<tr>
<td>superadmin</td>
<td>superadmin</td>
<td>ROLE_SUPERADMIN</td>
</tr>
</table>
<p>so you can login as each user to test the secured actions:</p>
<div class="syntax_hilite">
<div id="java-48">
<div class="java"><span style="color: #000099; font-weight: bold;">class</span> SecureController <span style="color: #000000;">&#123;</span></p>
<p>&nbsp; &nbsp;def index = <span style="color: #000000;">&#123;</span><span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;@Secured<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#91;</span><span style="color: #0000ff;">'ROLE_USER'</span><span style="color: #000000;">&#93;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;def user = <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp;...<br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;@Secured<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#91;</span><span style="color: #0000ff;">'ROLE_ADMIN'</span><span style="color: #000000;">&#93;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;def admin = <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp;...<br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span></p>
<p>&nbsp; &nbsp;@Secured<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#91;</span><span style="color: #0000ff;">'ROLE_SUPERADMIN'</span><span style="color: #000000;">&#93;</span><span style="color: #000000;">&#41;</span><br />
&nbsp; &nbsp;def superadmin = <span style="color: #000000;">&#123;</span><br />
&nbsp; &nbsp;...<br />
&nbsp; &nbsp;<span style="color: #000000;">&#125;</span><br />
<span style="color: #000000;">&#125;</span></div>
</div>
</div>
<p></p>
<p>Logout in between by navigating to <a target='_blank' href='http://localhost:8080/hierarchical/logout'>http://localhost:8080/hierarchical/logout<img src='/blog/images/pop.gif'/></a>. Although only one role is defined for each action, as the super admin you can access all three, as the admin you can access <code>admin</code> and <code>user</code>, and as the user you can only access <code>user</code>.</p>
<hr />
<p>I'll make this part of the plugin at some point to make configuration simpler, but for now it's not much work to do it explicitly.</p>
]]></content:encoded>
			<wfw:commentRss>http://burtbeckwith.com/blog/?feed=rss2&amp;p=275</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
