Grails CamelCase Sensitivity

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.

Safari Not Working, But Firefox Does

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

Select System Preferences

2. Click on the "Network" icon.

3. At the top select "Edit Locations..." from the Location drop down.

Edit Locations

4. Click the plus sign to add a new location and name it something like "home" or "work." Then, click "Done."

New Location

5. That should be it. Safari should work now.

 

Selecting Popup Windows in Selenium

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.

  • junit-4.8.2.jar
  • selenium-java-2.17.0.jar
  • selenium-server-standalone-2.17.0.jar

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)

Fixed: OpenOffice “Restore Windows” Popup

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.

OpenOffice Restore Windows Popup Image

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

 

How to setup a clustered Quartz scheduler in Grails 2.0.0

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.

Grails 2.0.0 lib directory fix

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

[UITableViewController loadView] loaded the “some-id” nib but didn’t get a UITableView.

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.

 

How to configure “Cross-cell single sign-on” in WebSphere with Jython

To configure "Cross-cell single sign-on" in the WebSphere 6.1 admin console with a Jython script, you can use the script below. This assumes that you've exported the keys from the server you are going to connect to.

import java.lang.String as jstr
import java.util.Properties as jprops
import java.io as jio
import javax.management as jmgmt

keyfilepassword = "somepassword"

# Import LTPA Keys
AdminConfig.save(); # This needs to happen so you can write to the Security file.
keyFile = "C:/projects/custom-security/was61keys";
fin = jio.FileInputStream(keyFile);
wasdev61keys = jprops();
wasdev61keys.load(fin);
fin.close();
password = jstr(keyfilepassword).getBytes();
securityAdmin = AdminControl.queryNames('*:*,name=SecurityAdmin');
securityObjectName = jmgmt.ObjectName(securityAdmin);
params = [wasdev61keys, password];
signature = ['java.util.Properties', '[B'];
AdminControl.invoke_jmx(securityObjectName, 'importLTPAKeys', params, signature);

# Save Config at the end.
AdminConfig.save();

How to configure a Shared Library in WebSphere with Jython

Here's a script that I used to configure a Shared Library in WebSphere 6.1 using Jython.

from string import whitespace

sharedLibName = "APPLICATION_SHARED_LIB"

# See if library already exists.
cellId = AdminConfig.list("Cell")
sharedLibraryId = AdminConfig.list("Library")
if (sharedLibraryId.find(sharedLibName) < 0): # Library does not exist.
	print "Creating Shared Library"
	params = [];
	params.append(["name", sharedLibName]);
	sharedLibraryId = AdminConfig.create("Library", cellId, params);

	# Find PARENT_LAST class loader
	print "Finding Class Loader"
	parentLastClassLoader = None;
	classLoaders = AdminConfig.list("Classloader")
	classLoaders = classLoaders.split();
	for classLoader in classLoaders:
		mode = AdminConfig.showAttribute(classLoader, "mode");
		if (mode == "PARENT_LAST"):
			parentLastClassLoader = classLoader;
			print "Found Parent Last Class Loader: " + classLoader;
	# Create a class loader
	if (parentLastClassLoader == None):
		print "Creating Class Loader";
		applicationServer = AdminConfig.list("ApplicationServer")
		params = [];
		params.append(["mode", "PARENT_LAST"]);
		parentLastClassLoader = AdminConfig.create("Classloader", applicationServer, params)
		print "Created Parent Last Class Loader: " + parentLastClassLoader;

	# Add the shared library to the class loader.
	params = [];
	params.append(["libraryName", sharedLibName]);
	params.append(["sharedClassloader", "true"]);
	AdminConfig.create("LibraryRef", parentLastClassLoader, params)

	print "Using Shared Library: " + sharedLibraryId;

	# Set a WAS variable to point to SharedLib
	print "Update the Variable Map"
	variableMap = AdminConfig.list("VariableMap").split();
	# Find the variable map for the server.
	for v in variableMap:
		if (v.find("/server") >= 0):
			variableMap = v
	print "Updating Variable Map: " + variableMap
	params = [];
	params.append(["symbolicName", "APP_SHARED_LIB_PATH"]);
	params.append(["value", "${APP_PROJECTS_ROOT}/SharedLib/MyApp"]);
	params.append(["description", "Root folder containing shared libs"]);
	AdminConfig.create("VariableSubstitutionEntry", variableMap, params);

	# Add all of our shared libs to Shared Library
	print "Adding Classpath";
	classpath = []
	classpath.append("${APP_SHARED_LIB_PATH}/activation.jar")
	classpath.append("${APP_SHARED_LIB_PATH}/commons-lang-2.1.jar")
	classpath.append("${APP_SHARED_LIB_PATH}/commons-logging.jar")
	classpath.append("${APP_SHARED_LIB_PATH}/dom4j-1.6.1.jar")
	classpath.append("${APP_SHARED_LIB_PATH}/smtp.jar")
	classpathStr = ""
	for c in classpath:
		if len(classpathStr) > 0:
			classpathStr += ";";
		classpathStr += c;
	params = [];
	params.append(["classPath", classpathStr]);
	AdminConfig.modify(sharedLibraryId, params);

# Save Config at the end.
AdminConfig.save();

How to configure WebSphere Global Security to use LDAP with Jython

Here's a script that I used to configure the WebSphere 6.1 global security setting to use LDAP using Jython.

# Properties
username = "user"
password = "pass"
ldapServer = "somecompany.com"
ldapPort = "389"

# Configure the LDAP authentication
AdminConfig.save(); # This needs to happen so you can write to the Security file.
ltpa = AdminConfig.list("LTPA");
ldapUserRegistry = AdminConfig.list("LDAPUserRegistry");
params = [];
params.append(["primaryAdminId", username]);
params.append(["useRegistryServerId", "false"]);
params.append(["type", "ACTIVE_DIRECTORY"]);
params.append(["realm", ldapServer + ":" + ldapPort]);
params.append(["baseDN", "DC=somecompany,DC=com"]);
params.append(["bindDN", "CN=" + username + ",OU=Service Accounts,DC=somecompany,DC=com"]);
params.append(["bindPassword", password]);
AdminConfig.modify(ldapUserRegistry, params);
# Configure the LDAP Advanced Settings
ldapSearchFilter = AdminConfig.list("LDAPSearchFilter");
params = [];
params.append(["userFilter", "(&(sAMAccountName=%v)(objectcategory=user))"]);
params.append(["groupFilter", "(&(cn=%v)(objectcategory=group))"]);
params.append(["userIdMap", "user:sAMAccountName"]);
params.append(["groupIdMap", "*:cn"]);
params.append(["groupMemberIdMap", "memberof:member"]);
params.append(["certificateMapMode", "EXACT_DN"]);
params.append(["certificateFilter", ""]);
AdminConfig.modify(ldapSearchFilter, params);
# Configure the LDAP endpoint.
endpointStr = AdminConfig.showAttribute(ldapUserRegistry, "hosts");
endpointStr = endpointStr[1:len(endpointStr)-1];
endpoint = endpointStr.split(' ')[0];
print endpoint
params = [];
params.append(["host", ldapServer]);
params.append(["port", ldapPort]);
AdminConfig.modify(endpoint, params);

# Configure Global Security
security = AdminConfig.list("Security") # ex. (cells/CompNode10Cell|security.xml#Security_1)
params = [];
params.append(["enabled", "true"]);
params.append(["appEnabled", "true"]);
params.append(["enforceJava2Security", "false"]);
params.append(["activeUserRegistry", ldapUserRegistry]);
params.append(["activeAuthMechanism", ltpa]);
AdminConfig.modify(security, params);

# Save Config at the end.
AdminConfig.save();