You are currently browsing the category archive for the ‘Seaside’ category.

Most of us recognize that static files do not need to be served from Seaside, but it is a step that can be easily overlooked. I was recently helping someone analyze performance for a Seaside application and we found that serving the initial page made 20 Seaside requests, all but one of them for something in /files (i.e., a subclass of WAFileLibrary). In this case it was Scriptaculous, but it could be anything.

The first step to fix this is to find out which files are being served from Seaside. You can do this by looking at your web server logs or by looking at requests made by the browser (in Firefox, use Firebug). If you see SUDevelopmentLibrary being requested, then look for references to that class. Typically the class will be the argument to an #’addLibrary:’ message following a #’register:asApplicationAt:’ message. Remove the #’addLibrary:’ call and re-register your application.

Second, create operating system files containing the material previously served by Seaside. You can copy the text from the methods or you can obtain the files elsewhere. For example, to replace SUDevelopmentLibrary, go to the Scriptaculous downloads page. Note, however, that SUDevelopmentLibrary has an additional method, #’treePatchJs’, that is not included in the download. Typically these files would be placed in your web server’s /scripts directory.

Finally, add references to the static file(s) to your component. Typically this is done in #’updateRoot:’ on your component. For example:

	#('prototype.js' 'scriptaculous.js' 'treePatch.js') do: [:each | 
		anHtmlRoot script
			url: '/scripts/scriptaculous/' , each;

With this, we reduced by 95% the number of pages served by Seaside!

In Chapter 12 of my Seaside Tutorial I give an example of rendering different content for a web site based on whether the user is known or not. This allows you to provide a public view (for un-authenticated users) and appropriate private views (for authenticated users), but requires you to to manage your own login dialog.

Seaside has the built-in ability to use HTTP Authentication to restrict an application to a specific user/password. The method WAAdmin class>>#’register:asApplicationAt:user:password:’ registers the application with WAAuthenticationFilter as a filter and provides a single user and password that must be provided in order to view the initial page. This provides some password security, but does not differentiate among allowed users (e.g., everyone will use the same ‘admin’ user name).

If you have an application that will always require authentication but should differentiate among multiple users, you can use WAAuthenticationFilter as well. For example, if you have a subclass of WAComponent named HelloComponent, you could provide a class-side initialization method as follows:

"HelloComponent initialize."
 | application filter |
 application := WAAdmin 
 register: self
 asApplicationAt: 'hello'.
 filter := WAAuthenticationFilter new
 authenticator: self;
 application addFilter: filter.

Like Seaside’s default authentication approach, this method adds a WAAuthenticationFilter as a filter, but provides an override to the default authenticator (here the component class itself). The authenticator must implement #’verifyPassword:forUser:’. The class side of HelloComponent could have something more sophisticated than the following:

verifyPassword: password forUser: username
 username = 'bert' ifTrue: [^password = 'ernie'].

At this point your render code can assume that a valid user has been properly authenticated and can vary the content based on the user. For example, the following instance-side method in HelloComponent would show what user was authenticated:

renderContentOn: html
 html text: 'Hello ' , self requestContext request user , '!'.

Now you have basic HTTP authentication for multiple users. Of course, you are now subject to the limitations of basic HTTP authentication, including the fact that logout is somewhat awkward. You can provide a logout link:

renderContentOn: html
 html text: 'Hello ' , self requestContext request user , '!'; break.
 html anchor
 callback: [self doLogout];
 with: 'Logout'.

The logout method informs the user how to complete the logout and then adds a field to let the verification method know to fail:

	| url |
	self inform: 'When the login dialog appears, click the Cancel button then close your browser.'.
	url := self requestContext request url copy.
	url addField: 'logout'.
	self requestContext redirectTo: url.

The verification method would then check for the new field:

verifyPassword: password forUser: username
 (WACurrentRequestContext value request url queryFields includesKey: 'logout') ifTrue: [^false].
 username = 'bert' ifTrue: [^password = 'ernie'].

Charlie Meyer has an explanation of how he used a similar approach with LDAP authentication.

Earlier I described how to migrate to a Metacello-based Seaside 2.8. The process involves removing many packages and loading things as if you were in a new repository. Because of the extensive package restructuring and class changes, the process of moving from Seaside 2.8 to 3.0 is largely the same. I’ve found that the same instructions work with one change: In step #13, evaluate ‘UpgradeTool new updateProjects; updateGLASS; loadSeaside30’ in a workspace to load Seaside.

After doing the load, I found a few packaging issues:

  • ‘Metacello-MC’ was marked dirty but had no changes. I reloaded it to clear the dirty flag.
  • ‘Seaside2’ existed but had no repositories or versions. I unloaded the package.
  • ‘Seaside-Core.gemstone’ was missing WAAuthConfiguration. I reloaded the package.
  • ‘Seaside-Component’ was dirty but had no changes. I reloaded it to clear the dirty flag.
  • ‘Seaside-Tools-Core’ was dirty but had no changes. I reloaded it to clear the dirty flag.
  • ‘VB-Regex’ existed but was replaced by ‘Regex-Core’ and ‘Regex-Tests-Core’. I unloaded it.

With this, I have Seaside 3.0 loaded (but not running). There are a substantial number of changes between Seaside 2.8 and Seaside 3.0, so much work remains to be done–but at least we have the code loaded!

There are instructions for loading Seaside 3.0 into GemStone, but there are a couple bugs (including #259 and #278) that get in the way when loading Seaside 3.0.5 into GemStone I’ve found that the following Smalltalk code (used in Topaz or a workspace) allows a successful load:

ConfigurationOfGLASS project updateProject.
ConfigurationOfGofer project updateProject.
ConfigurationOfGoferProjectLoader project updateProject.
ConfigurationOfGsCore project updateProject.
ConfigurationOfGsMisc project updateProject.
ConfigurationOfGsMonticello project updateProject.
ConfigurationOfGsOB project updateProject.
ConfigurationOfMetacello project updateProject.
System commitTransaction.

MCPlatformSupport autoMigrate: true.
ConfigurationOfMetacello project latestVersion load.
ConfigurationOfGoferProjectLoader project load: #stable.
MCPlatformSupport autoMigrate: false.
System commitTransaction.

MCPlatformSupport commitOnAlmostOutOfMemoryDuring: [
		ConfigurationOfGLASS project load: #stable.
	] on: Warning do: [:ex | ex resume ].
System commitTransaction.

MCPlatformSupport commitOnAlmostOutOfMemoryDuring: [
		Gofer project load: 'Seaside30' version: '3.0.5'.
	] on: Warning do: [:ex | ex resume ].
System commitTransaction.

I have updated this tutorial to Seaside 3.0 using the Seaside One-Click Experience in Pharo. It will be the basis for a half-day tutorial at Smalltalk Solutions next month.

The original version(s) of GLASS took a ‘kitchen-sink’ approach Seaside–everything was included, including available add-ons (such as Pier) and samples (such as the sushi store). This made it very easy to start playing with Seaside on GemStone, but makes upgrades rather awkward since it isn’t always clear which versions of which packages should be loaded together. And this is the problem that Metacello was designed to solve.

Starting with GemStone, the provided image (extent0.seaside.dbf) does not have Seaside loaded, but loading either Seaside 2.8 or Seaside 3.0 is relatively easy. The problem, is that there may be many packages you wish to unload to achieve the ‘tidy’ approach now encouraged by Metacello.

This blog post describes one such path to upgrading that I’ve used successfully.

  1. Make a backup of your system and test the following on a copy of your production system.
  2. Log in to GemStone and stop other sessions (‘System stopUserSessions’).
  3. Add to your list of Monticello repositories.
  4. Load the UpgradeTool package, giving you the UpgradeTool class.
  5. Copy the shell script in the #’shellScriptForInstallGLASS’ method.
  6. In a workspace, execute ‘UpgradeTool new doRemoveTasks’ to remove GLASS-related classes and methods.
  7. Log out of GemStone.
  8. In a bash shell, set the GEMSTONE environment variable (and PATH to include $GEMSTONE/bin), then paste the shell script code copied earlier.
  9. Review the log file to see that the script ended with an errorCount of zero (0).
  10. Log in to GemStone and turn off auto-migrate (we will do a bulk-migrate later).
  11. Re-add the GLASS repository as well as any of your application repositories.
  12. Load the UpgradeTool package as well as all of your application packages. The load should not change any code, but will add the packages to the list of loaded packages.
  13. In a workspace, execute ‘UpgradeTool new loadSeaside28’ to load the base Seaside.
  14. Load any other add-on packages (for example, SeasideAsync.g).
  15. Seaside 2.8 is now loaded, but your existing subclasses still have the old superclass. In a workspace, execute ‘UpgradeTool new doCleanupTasks’ to recompile classes and migrate instances.
  16. Check UndefinedSymbols to see that the size is only one (1)–the dictionary itself. If there are other names present, then you probably need to load additional packages and repeat the cleanup step.
  17. Initialize your Seaside applications to reregister them as visible applications.
  18. Restart the web server (Hyper or FastCGI) and try things out!

This should give you a database with your classes and data still present, but the surrounding Seaside framework should be much cleaner. Now you can start thinking about migrating to Seaside 3.0 (more on this later!).

James Robertson is applying his considerable experience creating screencasts to new areas, including a three-minute Getting Started with GLASS. Check it out!

Learning Web Development with Seaside is a series of 16 lessons totaling about 150 pages of detailed instructions that walk you through the steps involved in various aspects of building a web application with Seaside. Videos of a number of chapters are available. The videos are highly edited so that they provide a very quick overview of each activity.

You watch them on YouTube by following the links above or you can download the .mov files directly here.