Wednesday, May 5, 2010

IPP IFrame Grails Printing with Tabs

Step 0:
First thing's first: IE7 + Iframe + window.print() = non-functioning print button. The solution for this is to use: document.execCommand('print', false, null);

Now that that's out of the way.

For our Grails page we are using tabs (yui 2.7.0.1) to organize and display things in a more user-friendly fashion. The problem with this comes when you're ready to print. There have been several solutions (none of them pretty) that I've come across that have attempted to solve this problem. With the help of Heidi, we have come up with one more:

Step 1: Print Button


This can also be done with a link:
<a onclick="document.execCommand('print', false, null);" href="#">PRINT</a>


Step 2: print.css
You need to fix your style sheet to remove the yui tabs and display the content in-line. This is what worked for us in IE7.

.buttons {
display: none;
}

.yui-navset .yui-content .yui-hidden {
border:0;
height:100%;
width:100%;
padding:0;
position:relative;
left:0px;
overflow:auto;
visibility:visible;
}

.dialog table {
padding: 0;
border:0;
}

If you're using firefox you need to add:

.tabInner {
display: none;
}

3. Make sure this tab removal only happens when you're printing:
<link rel="stylesheet" type="text/css" href="css/print.css" media="print">


And you're done! Please feel free to share other solutions you've found when printing. I'm always looking for a better, more eloquent solution.

Brandy

Wednesday, April 28, 2010

Mock Testing with Grails

For unit testing controllers that make calls to injected spring beans, we can use Grails' mock framework.

Take for example a Controller and Service class defined as follows
class MyService {
boolean transactional = true

def serviceMethod(param1) {
return 'hi'
}
}

class MyDomainController {
def myService

def doSomething = {
def val = myService.serviceMethod('input1')
return val }
}

Our test case for the doSomething closure would look as follows
import grails.test.*

class MyDomainControllerTests extends ControllerUnitTestCase {

protected void setUp() {
super.setUp()
}

protected void tearDown() {
super.tearDown()
}

void testSomething() {
GrailsMock serviceMock = mockFor(MyService)

/*
* Mock the method being called
* the 1..1 specifies the min & max number of times the method is expected to be called
* the closure defines the code executed each time the method is called
*/

serviceMock.demand.serviceMethod(1..1) {param1 ->
assertEquals 'input1', param1
return 'hi'
}

/*
* The service needs to be manually set in the controller
*/

controller.myService = serviceMock.createMock()

assertEquals 'hi', controller.doSomething()

/*
* Verifies that the service was accessed
* in the manner established earlier.
*/

serviceMock.verify()
}
}

Wednesday, April 14, 2010

Bypassing Acegi Security

Acegi Security is rather easy to include in your application, but because our application needs to integrate with a single-sign on system, some method of bypassing Acegi or automatically logging into our application is required.

Since Acegi is built upon a list of filters that intercept HttpServletRequests, we can inject our own filter into the chain that will automatically log a user into our application. For simplicity, we assume the SSO is providing user information in a request header parameter.

The first step is include our filter in the list of filters to be invoked by Acegi. Edit conf\SecurityConfig.groovy, which should have been created during installation of the Acegi plugin, to include the following:
filterNames = ['httpSessionContextIntegrationFilter',
'logoutFilter',
'authenticationProcessingFilter',
'securityContextHolderAwareRequestFilter',
'rememberMeProcessingFilter',
'mySsoFilter',
'anonymousProcessingFilter',
'exceptionTranslationFilter',
'filterInvocationInterceptor']

The filters listed are the common filters invoked by Acegi in the listed order. We've included our filter mySsoFilter.


Since the filters in Acegi are actually Spring beans, the next step is to define the bean representing our filter in conf\spring\resources.groovy
mySsoFilter(MySsoFilter) {
userDetailsService = ref("userDetailsService")
}

The userDetailsService bean passed to our filter is pre-defined by Acegi and Grails. It's purpose is described later.


Finally we create our filter file, MySsoFilter.groovy, in the utils directory. The skeleton is listed below. Note
-- we defined an instance field userDetailsService, the Spring bean injected into our filter bean.
-- the method getOrder() defines the order and priority for the filter during invocation
-- the method doFilterHttp(...) is where the functionality of our filter will be contained.
import org.apache.commons.logging.LogFactory

import org.springframework.beans.factory.InitializingBean
import org.springframework.security.GrantedAuthority
import org.springframework.security.GrantedAuthorityImpl
import org.springframework.security.context.SecurityContextHolder
import org.springframework.security.providers.UsernamePasswordAuthenticationToken
import org.springframework.security.ui.FilterChainOrder
import org.springframework.security.ui.SpringSecurityFilter

import javax.servlet.FilterChain
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse


class MySsoFilter extends SpringSecurityFilter implements InitializingBean
{
static final HEADER_ATTRIBUTE_LOGIN = 'x-login'
static final HEADER_ATTRIBUTE_FIRSTNAME = 'x-firstname'
static final HEADER_ATTRIBUTE_LASTNAME = 'x-lastname'
static final HEADER_ATTRIBUTE_EMAIL = 'x-email'

static final log = LogFactory.getLog(MySsoFilter.class)

def userDetailsService

void afterPropertiesSet() {
log.debug '************************ inside afterPropertiesSet'
}


void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
chain.doFilter(request, response)
}

int getOrder() {
return FilterChainOrder.REMEMBER_ME_FILTER
}
}



Now that we have a filter being invoked in the proper order, containing information about the user who has been logged in via SSO, the difficulty now lies in simulating a login in Acegi.

First, we get information about the user we're trying to log in. This is provided by the userDetailsService bean, an instance of the Acegi implementation of the UserDetailsService. The interface's only method returns an instance of UserDetails, which is a wrapper around the loginUserDomainClass and authorityDomainClass defined during Acegi installation (and also defined in SecurityConfig.groovy).
def details = userDetailsService.loadUserByUsername(username) 


Next, we create a security token, by using the concrete class UsernamePasswordAuthenticationToken. The password is obtained during lookup of the user.
def token = new UsernamePasswordAuthenticationToken(
details, passwd, details.authorities)


Finally, we give the token to the SecurityContextHolder, an Acegi object which manages the security token per executing thread.
SecurityContextHolder.context.authentication = token 



Our final implementation for doFilterHttp(...) is as follows
    void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {
log.debug '************************ inside doFilterHttp'
log.debug 'req value ' + request.getHeader(HEADER_ATTRIBUTE_LOGIN)

// no SSO header, do not continue
def login = request.getHeader(HEADER_ATTRIBUTE_LOGIN)
if (!login) {
log.debug('no sso header found, continuing')
chain.doFilter(request, response)
return
}

// user not in our system, do not continue
def user = User.findByUsername(login)
if (!user) {
log.info('username ' + login + ' not found')
chain.doFilter(request, response)
return
}

// user does not have admin role, do not continue
def adminRole = Role.findByAuthority('ROLE_ADMINISTRATOR')
if (!user.authorities.contains(adminRole)) {
log.info('user ' + login + ' does not have admin permission')
chain.doFilter(request, response)
return
}

log.info('user ' + login + ' given SSO access')
def details = userDetailsService.loadUserByUsername(user.username)
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
details, user.passwd, details.authorities)
SecurityContextHolder.context.authentication = token
chain.doFilter(request, response)
}

Tuesday, April 13, 2010

GrailsUI Tab Manipulation

We've been using the Tab Layout available in the GrailsUI plugin in our application, but one minor annoyance we've discovered is that while saving the form resets the active tab.

The javascript library that renders the tabs gives you access to the tab information, through the variable GRAILSUI

For example, the following gsp would always display the first tab on save.

<gui:tabView id="myTabs">
<gui:tab label="Basic" active="true">
</gui:tab>
<gui:tab label="Firms">
</gui:tab>
</gui:tabView>



We can now access the tabs in custom javascript by using
GRAILSUI.myTabs.get('activeIndex')


all that's left is to save a hidden field, and change the tab 'active' definitions

Custom Grails Error Handling

Error handling in your Grails app is especially important, as Groovy is a non-checked language -- methods need not declare a throws clause. While UrlMappings.groovy provides a default page for general 500 errors, in our application, we'd like to display different error pages in different situations.

There are several approaches to this problem. One solution is to separate error handling by exception class. This can be done by modifying Bootstrap.groovy

exceptionHandler is an instance of GrailsExceptionResolver, and can be auto injected. Note the last entry is needed for default handling.

Also, be sure to remove the "500" entry from UrlMappings.groovy, as interferes with the definitions here.

class BootStrap {
def exceptionHandler

def init = {
exceptionHandler.exceptionMappings = [
'SpecialException' : '/myController/someAction',
'java.lang.Exception' : '/error'
]
}
}



Another approach is to modify the handling in UrlMappings.groovy. By default, the "500" entry points to error.gsp in the views directory, but it can be changed to another view, or a controller with optional action specified.
"500"(controller:'myController', action:'handleExceptions')

Monday, March 22, 2010

Calling Stored Procedures in Groovy

As expected, Groovy provides some compact syntax for calling stored procedures. All the magic is contained in the Sql class.

For example, a stored procedure with the following signature:
insert_book(p_title IN VARCHAR2, p_author IN VARCHAR2, p_isbn OUT VARCHAR2, p_id OUT INTEGER)


Can be invoked with the following Groovy code:
public saveBook(book) {
def isbn
def bookId

Sql sql = new Sql(dataSource)
sql.call "{insert_book(?, ?, ?, ?)}",
[book.title, book.author, Sql.VARCHAR, Sql.INTEGER],
{ spIsbn, spId ->
isbn = spIsbn
bookId = spId
}
}

Note:
  • the first parameter is a string containing the stored proc call that also parameterizes the in/out variables.
  • the second parameter are the variables to be passed in or the corresponding type of the out parameter
  • the third parameter is a closure that is given the out parameters of the executed stored procedure in the order they are declared in the sproc.
dataSource is an instance of the data source created in DataSource.groovy. Our snippet assumes the saveBook method is contained in a spring bean, where the dataSource variable can be automatically injected.


More information on Groovy and db objects can be found here.

Thursday, March 4, 2010

Mapping Domain Classes with Hibernate Annotations

Save the following file as grails-app/conf/hibernate/hibernate.cfg.xml. Note that it specifies a single class being mapped, all classes in a package can be specified by using:

<mapping package="com.test.domain" />


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>

<session-factory>
<mapping class="Firm"/>
</session-factory>

</hibernate-configuration>

Our domain class looks as follows. Note that the table name is a Oracle Database Link.

import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.Id
import javax.persistence.Table

@Entity()
@Table(name="firm@remote")
class Firm {
@Id
Integer id
@Column(name="name")
String name
@Column(name="status")
String status

@Column(name="key")
String key
@Column(name="short_name")
String shortName
}