One way to pass the model set in your view GSP is to use ${pageScope.variables}.
Here’s an example:
<g:render template="/layouts/controlbar" model="${pageScope.variables}"/>
One way to pass the model set in your view GSP is to use ${pageScope.variables}.
Here’s an example:
<g:render template="/layouts/controlbar" model="${pageScope.variables}"/>
I installed the Grails zipped-resources plugin on a new project the other day, and I noticed that by default it zips up everything it sends.
This is fine, but when I tried to make it ignore the image files being served up, it wasn’t obvious at first how to do that. Finally, I figured out what I needed to do. Adding the following line to my Config.groovy excluded the image files from being zipped up.
grails.resources.mappers.zip.excludes = ['**/*.png','**/*.gif','**/*.jpg','**/*.jpeg','**/*.gz','**/*.zip']
Once I read more about defining a mapper, it was nice to see that even configuration of these resource files was taking on a convention.
That said, the suite of resources plugins that are coming out now for Grails are very useful. I would say that they really help make Grails a strong contender in platform choices for the future.
I ran into an weird bug today that took awhile to figure out. Basically, I was getting the error when I deployed some grails code to a linux box.
In the error log, this is what showed up:
ERROR view.ScaffoldingViewResolver - Error generating scaffolded view [/BNice/index]: /opt/grails-1.3.7/src/grails/templates/scaffolding/index.gsp (No such file or directory) java.io.FileNotFoundException: /opt/grails-1.3.7/src/grails/templates/scaffolding/index.gsp (No such file or directory) at java.io.FileInputStream.open(Native Method) at java.io.FileInputStream.<;init>;(FileInputStream.java:120) at org.grails.plugin.resource.DevModeSanityFilter.doFilter(DevModeSanityFilter.groovy:44) at java.lang.Thread.run(Thread.java:680)
And, in the HTML response, this is what showed up:
HTTP status 404 - /testapp/WEB-INF/grails-app/views/BNice/index.jsp type: Status report message: /testapp/WEB-INF/grails-app/views/BNice/index.jsp description: The requested resource (/testapp/WEB-INF/grails-app/views/BNice/index.jsp) is not available.
It took a while, but I finally figured out that it had nothing to do with the server setup, but was in fact an issue with the code.
In the project, there was a controller called “BNiceController”. When grails sees to capital letters in the beginning of a name, the CamelCasing of the controller and the views must be exactly like first part of the controller.
Here’s how a normal reference would look for a controller called BeNiceController.
// In the gsp, the controller would be referenced like so:
${createLink(controller: 'beNice')}
// The view would be located in /grails-app/views/beNice/index.gsp
However, if the controller is called BNiceController, this is what you would have to do. Notice, the folder in the views directory is “BNice”.
// In the gsp, the controller would be referenced like so:
${createLink(controller: 'BNice')}
// The view would be located in /grails-app/views/BNice/index.gsp
It’s kind of annoying. I wish this wasn’t the default behavoir.
I recently had a problem on my Macbook where Safari would stop working after a few minutes of connecting to the network, but other network applications, like Firefox, still worked. It was odd. Safari would just sit and hang.
After some research, what ended up working for me was to create a new network profile. Here are the steps to do that in Mac OSX (10.7.2).
1. Go to the Apple Menu in the upper left and choose
2. Click on the “Network” icon.
3. At the top select “Edit Locations…” from the Location drop down.
4. Click the plus sign to add a new location and name it something like “home” or “work.” Then, click “Done.”
5. That should be it. Safari should work now.
This example shows how to start a Selenium Server and run a Selenium client in Java. The example opens up a popup window by clicking on the link in index.html. It then selects the popup window by first using the “name=popupWindowName” option for selectWindow. It then grabs the original window (using “name=null”). And, finally, it grabs the popup again by using the global javascript variable option in selectWindow (“var=popupWindowVar”).
In order to run this test, you will need the following three jar files on your classpath.
Unit Test
package org.example;
import static org.junit.Assert.assertEquals;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.openqa.selenium.server.RemoteControlConfiguration;
import org.openqa.selenium.server.SeleniumServer;
import com.thoughtworks.selenium.DefaultSelenium;
public class SeleniumIntegrationTest {
private static SeleniumServer server = null;
private DefaultSelenium selenium = null;
@BeforeClass
public static void oneTimeSetUp() throws Exception {
// Create a configuration to override defaults.
RemoteControlConfiguration rcc = new RemoteControlConfiguration();
rcc.setTimeoutInSeconds(60);
rcc.setPort(4444);
rcc.setSingleWindow(true); // Support Popups
rcc.setTrustAllSSLCertificates(true); // Trust SSL
// Start the Selenium Server.
server = new SeleniumServer(false, rcc);
server.start();
}
@AfterClass
public static void oneTimeTearDown() throws Exception {
server.stop();
}
@Before
public void setUp() throws Exception {
// // Create a Selenium thread.
// // Open in Chrome
// selenium = new DefaultSelenium("localhost", 4444,
// "*googlechrome",
// "http://localhost:8080/GrailsDefault/");
// // Open in Safari
// selenium = new DefaultSelenium("localhost", 4444,
// "*safari C:\\Program Files (x86)\\Safari\\Safari.exe",
// "http://localhost:8080/GrailsDefault/");
// // Open in IE
// selenium = new DefaultSelenium("localhost", 4444,
// "*iexplore",
// "http://localhost:8080/GrailsDefault/");
// Open in Firefox
selenium = new DefaultSelenium("localhost", 4444,
"*firefox3",
"http://localhost:8080/GrailsDefault/");
// Start the server
selenium.start();
}
@After
public void tearDown() {
// Stop the Selenium thread.
selenium.stop();
}
@Test
public void popupWindowExample() {
// Open the base window.
selenium.open("index.html");
assertEquals(selenium.getTitle(), "Popup Window Example");
// Click button to popup new window.
selenium.click("id=popupButton");
// Select the popup window.
// popupWindowID is the ID given in the window.open javascript.
selenium.waitForPopUp("popupWindowID", "30000");
selenium.selectWindow("name=popupWindowID");
assertEquals(selenium.getTitle(), "Popped Up Window");
// Click a link to google on the popup.
selenium.click("link=This link goes to google");
selenium.waitForPageToLoad("30000");
assertEquals(selenium.getTitle(), "Google");
// Select the original window.
selenium.selectWindow("null");
assertEquals(selenium.getTitle(), "Popup Window Example");
// Select the window by a javascript variable.
selenium.selectWindow("var=popupWindowVar");
assertEquals(selenium.getTitle(), "Google");
}
}
index.html
<html>
<head>
<title>Popup Window Example</title>
<script>
function popupNewWindow() {
window.popupWindowVar = window.open("popup.html", "popupWindowID");
}
function popupNewWindow2() {
window.popupWindowVar2 = window.open("popup.html", "popupWindowID2");
}
</script>
</head>
<body>
<div id="header">
<button id="popupButton" onclick="popupNewWindow()">Popup Window</button>
<button id="popupButton2" onclick="popupNewWindow2()">Popup Window 2</button>
</div>
</body>
</html>
popup.html
<html> <head> <title>Popped Up Window</title> </head> <body> <div id="header"> This is a popup window. </div> <div id="links"> <a href="http://www.google.com">This link goes to google</a>. </div> </body> </html>
I found a bug in the variation of selectWindow that tries to grab the window from a JavaScript variable (i.e “var=foo”). It works in Chrome and IE. However, I could not get it working with Firefox 9.0.1 with Windows 7. The error is below. I’ve opened up a defect. The bug is listed here: http://code.google.com/p/selenium/issues/detail?id=3270.
com.thoughtworks.selenium.SeleniumException: ERROR: Window does not exist. If this looks like a Selenium bug, make sure to read http://seleniumhq.org/docs/04_selenese_commands.html#alerts-popups-and-multiple-windows for potential workarounds.
at com.thoughtworks.selenium.HttpCommandProcessor.throwAssertionFailureExceptionOrError(HttpCommandProcessor.java:112)
at com.thoughtworks.selenium.HttpCommandProcessor.doCommand(HttpCommandProcessor.java:106)
at com.thoughtworks.selenium.DefaultSelenium.selectWindow(DefaultSelenium.java:370)
at org.example.SeleniumIntegrationTest.popupWindowExample(SeleniumIntegrationTest.java:99)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
I tried starting Open Office on my Mac running 10.7.2, and I got this annoying popup window that won’t go away. I click on “Don’t Restore Windows” or “Restore Windows”, and it just stays popped up.
I found a solution though.
1) Force Quit your Open Office Application (Right-click holding the option key).
2) Open up Terminal and at the command prompt type to remove the Saved Application State information.
rm -rf "~/Library/Saved Application State/org.openoffice.script.savedState"
3) Start up OpenOffice and the popup should no longer show.
Hope that helps
In my steps below, I’m using Grails 2.0.0 and Quartz 2.1.1. I’m also connecting to a local DB2 database.
1. Run “grails clean” on your application.
2. Add the “quartz-all-2.1.1.jar” and “c3p0-0.9.1.1.jar” (in the lib folder of your Quartz download) to your lib directory.
3. Right click on your Grails project and chose “Grails Tools -> Refresh Dependencies” (Alt+G, R)
* Note: You will need run steps 1 – 3 in order to get Grails to link the dependencies.
4. Add your Quartz.properties file to your “conf” directory (or somewhere else on your classpath). Here’s the Quartz.properties file I used (you’ll need to change the username and password).
#============================================================================ # Configure Main Scheduler Properties #============================================================================ org.quartz.scheduler.instanceName = MyClusteredScheduler org.quartz.scheduler.instanceId = AUTO #============================================================================ # Configure ThreadPool #============================================================================ org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.threadCount = 25 org.quartz.threadPool.threadPriority = 5 #============================================================================ # Configure JobStore #============================================================================ org.quartz.jobStore.misfireThreshold = 60000 org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate org.quartz.jobStore.useProperties = false org.quartz.jobStore.dataSource = myDS org.quartz.jobStore.tablePrefix = QRTZ_ org.quartz.jobStore.isClustered = true org.quartz.jobStore.clusterCheckinInterval = 20000 #============================================================================ # Configure Datasources #============================================================================ org.quartz.dataSource.myDS.driver = com.ibm.db2.jcc.DB2Driver org.quartz.dataSource.myDS.URL = jdbc:db2://localhost:50001/BATCH org.quartz.dataSource.myDS.user = <some user> org.quartz.dataSource.myDS.password = <some password> org.quartz.dataSource.myDS.maxConnections = 5 org.quartz.dataSource.myDS.validationQuery=select 0 from dual
5. In your Config.groovy file, add or modify you “grails.config.locations” property. Here’s what I added:
grails.config.locations = [
"classpath:conf/Quartz.properties"
]
6. I added the JobScheduler and HelloJob java classes to my src/java directory. These could be groovy or whatever, but I just stole the example from Quartz to get it working correctly.
JobScheduler.java
package sample.quartz.scheduler;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;
import static org.quartz.CronScheduleBuilder.*;
import org.apache.log4j.Logger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;
public class JobScheduler {
private static Logger log = Logger.getLogger(JobScheduler.class);
private static JobScheduler JOB_SCHEDULER = new JobScheduler();
private Scheduler scheduler = null;
public JobScheduler() {
}
public static JobScheduler getInstance() {
return JOB_SCHEDULER;
}
public void startup() {
try {
// and start it off
scheduler = StdSchedulerFactory.getDefaultScheduler();
System.out.println("NAME: " + scheduler.getSchedulerName());
scheduler.start();
// define the job and tie it to our HelloJob class
JobDetail job = newJob(HelloJob.class)
.withIdentity("job1", "group1")
.build();
// Trigger a job that repeats every 20 seconds
Trigger trigger = newTrigger()
.withIdentity("trigger1", "group1")
.withSchedule(cronSchedule("0/20 * * * * ?"))
.build();
System.out.println("Starting Jobs");
// Tell quartz to schedule the job using our trigger
scheduler.scheduleJob(job, trigger);
scheduler.start();
} catch (SchedulerException se) {
se.printStackTrace();
}
}
public void shutdown() {
try {
scheduler.shutdown();
} catch (SchedulerException se) {
se.printStackTrace();
}
}
}
HelloJob.java
package sample.quartz.scheduler;
import java.util.Date;
import org.apache.log4j.Logger;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class HelloJob implements Job {
private static Logger log = Logger.getLogger(HelloJob.class);
public HelloJob() {
}
public void execute(JobExecutionContext context)
throws JobExecutionException {
System.out.println("Hello! HelloJob is executing. " + new Date());
}
}
7. In your BootStrap.groovy file, add…
import sample.quartz.scheduler.JobScheduler
class BootStrap {
def init = { servletContext ->
JobScheduler.getInstance().startup()
}
def destroy = {
JobScheduler.getInstance().shutdown()
}
}
That’s it! Start your server. I tested it by running two servers. So,
grails -Dserver.port=8080 run-app
and then
grails -Dserver.port=8090 run-app
You will see that the first server to come up will run the HelloJob.java. I then tested the cluster by shutting off the first server. The second server picked up the scheduler (within 20 seconds, since that’s what was specified in the property file) and started running with it.
One problem I ran into trying to set this up was the error below. I had forgotten to c3po-0.9.1.1.jar along with quartz-all-2.1.1jar to the lib directory. Once I did that (and refreshed the dependencies), this error went away.
Issue:
ERROR context.GrailsContextLoader - Error executing bootstraps: java.lang.NoClassDefFoundError: com/mchange/v2/c3p0/ComboPooledDataSource
Hope that helps.
I recently had a problem with Grails when I started a new project in Eclipse with Grails 2.0.0. I tried adding an external JAR file to my “lib” directory by dragging the JAR file over to the directory.
In Grails 1.3.7, the JAR file would then get added to the list of grails dependences (after refreshing the dependencies). However, that stopped working. After reading some user group posts, here’s what I did to fix it.
1) run “grails clean”
2) drag the jar file to your “lib” directory.
3) right-click on the project and choose Groovy Tools -> Refresh Dependencies
The following error occurred when adding a UIView to the root of a NIB expecting that was loaded by a UITableViewController class.
uncaught exception 'NSInternalInconsistencyException', reason: '-[UITableViewController loadView] loaded the "some-id" nib but didn't get a UITableView.'
If you have a UITableViewController and your root element is not a UITableView, you should make your controller extend UIViewController (not UITableViewController) and implement the UITableViewDelegate and UITableViewDataSource interfaces.
Your header file would look like this.
@interface ContactUsViewController : UIViewController<UITableViewDelegate, UITableViewDataSource> {
IBOutlet UITableView* tableView;
}
@property (nonatomic, retain) UITableView* tableView;
@end
You should also add a reference to the table so that you can access it in your implementation. You may have to extend the UITableView in order to extend the operations.