Wednesday, November 4, 2009

Standard Portlet Markup and CSS Classes

After reading Andy's slides on Annotation Driven Portlet Development with Spring, I ran across a post from Andy written earlier in the year called The Perfect Portlet Markup which provided an example of what he thought would be great markup, but was also mostly an attempt get people talking about what constitutes the perfect portlet markup.

Similar topics have been brought up on the Jasig lists (jasig-ui, portlet-dev), not even aiming for perfection, but at least some standardization, even if it is just for uPortal portlets.

First off, everyone should first read JSR-168 and JSR-286. These are the only standards I know about as of time of writing that refer to how (those types of) portlets should be written.

I shortened the styles defined in JSR-168 and JSR-286 PLT.C into the Portlet Styling Quick Reference while trying to understand these and use them. However, I learned in the process that it is highly disputed that the CSS classes/styles that they define in PLT.C are of much use.

In uPortal portlets hosted at Jasig up to date of writing, you’ll see a lot of non-semantic markup (basically everything is a div, which is not good) peppered with minimal usage of the PLT.C classes. This is not surprising, since even the WeatherPortlet provided by Sun when it introduced the specification doesn't use the classes defined in PLT.C.

I like that Andy is trying to nail down a standard. I’ve tried to also, and I know that others more talented than me with UI continue to try. But, the fact is that each portal’s portlets are going to be different and there is not really a good way to write a portlet that will render well in every (or even most) portal environments because of what many would argue to be the awful and outdated UI and CSS definitions in JSR-168 and JSR-286.

In uPortal 3.1, they’ve latched onto the FSS (Fluid Skinning System) which is non-standard across portals in an attempt to at least have some standardization in UI, even if it is only within uPortal and others that use FSS.

uPortal 3.1 also introduced a webapp to serve UI resources, which will also possibly make uPortal portlets a little less standard and less portable to other portal servers, even though image/javascript/CSS resource sharing is a good idea.

Something else to consider is that many have been using or are starting to use proxy portlets that pull in content served by Rails apps, PhP, etc. This could be the direction of things to come unless efforts to integrate other more dynamic languages into the portals themselves take hold.

Thursday, October 15, 2009

See Moving APRS Stations

There is a really neat site, aprs.fi, that provides information on those using the Automatic Packet Reporting System that displays tracking data using Google Maps. It even lists the APRS stations that are currently moving along with their speed, a comment, and the type of vehicle.

Wednesday, October 14, 2009

Include LICENSE and NOTICE in Your War or Jar File Automatically

Part of Apache 2.0 policy is to include the LICENSE and NOTICE files in any distribution.

If you would like to include these two files in your jar or war, and are using Maven 2 to build your project, then just use the tools-maven-plugin in your pom.xml:

1. Create a LICENSE and NOTICE file at the root of your project in the same directory as the pom.xml.

2. Add the plugin:


  ...
  <build>
    <plugins>
      ...
      <plugin>
         <groupId>org.apache.geronimo.genesis.plugins</groupId>
         <artifactId>tools-maven-plugin</artifactId>
         <executions>
             <execution>
                 <id>install-legal-files</id>
                 <phase>generate-resources</phase>
                 <goals>
                     <goal>copy-legal-files</goal>
                 </goals>
             </execution>
         </executions>
     </plugin>
     ...
    </plugins>
  </build>
  ...
3. You might want to also specify the version:

  ...
  <build>
     <pluginManagement>
         <plugins>
             ...
             <plugin>
                 <groupId>org.apache.geronimo.genesis.plugins</groupId>
                 <artifactId>tools-maven-plugin</artifactId>
                 <version>1.3.1</version>
             </plugin>
             ...
         </plugins>
     </pluginManagement>
     ...
  </build>
  ...

There is also a verify-legal-files goal, but it appears to look in the wrong place for the files in v1.3.1.

Note: if you are distributing a source and/or binary version of your project instead of just the war or jar (i.e. using zip, gz, tar, tar.gz, tar.bz2), you might want to use the maven-assembly-plugin to do this.

Tuesday, October 13, 2009

uPortal vs. Liferay Comparison

Someone recently asked on the uportal-user list for a comparison of uPortal 3.1.1 to Liferay 5.2.3. I'm not an expert on either, and this is just what I've noticed. Please jump in if I've left out anything, or if what I'm saying is incorrect. Note: his original question indicated that he was planning on integrating Shibboleth.

uPortal

Miscellaneous:

* By default uPortal uses CAS for authN. Some info for how to get Shibboleth setup is here: http://www.ja-sig.org/wiki/display/UPM31/03+Shibboleth and James Hong is the last one to indicate that he Shibbolized a recent version. We plan to eventually move to uP 3.1.1 (or later) and shibbolize it, but I just did a quick spike (test) of shibbing it (I wasn't able to keep it from hitting Login even on the guest view, but I'm guessing I was doing something wrong). If you have any trouble Shibbolizing, let the list know and maybe James can assist.
* uPortal has handful of portlets "under its wing" here: https://www.ja-sig.org/svn/portlets/ (note that not all of the portlets in the list at http://www.jasig.org/portlets are functional/have been tested in uPortal 3.1.1, but I assume the ones in https://www.ja-sig.org/svn/portlets/ have although I'm not sure totally. There are also a few built-in to the uPortal codebase itself (for administration, etc.).

Pros

* Community is more University/school focused: I think there are many more universities/schools using uPortal vs. those using Liferay, but it not strictly used by universities.
* Has a Jasig portlet adoption process so that if you do contribute something that you can help get to the point where it meets standards (including being Apache-licensed), you should have some help in maintaining it.
* Works closely with Fluid group, so there is innovation in development of UI that first was shown in uP 3.1.
* CAS is built-in. Since many use CAS, this is good for them!
* Webproxy portlet can be used to share existing/new web applications and web content in the portal (but you'd need to use CSS classes implemented in your uPortal skin(s)).
* They offer free use of their Jira, Confluence, and Subversion for portlet and uPortal-related project development and community frequently will work together on portlets.

Cons

* Not fully up-to-date on latest portlet standard: Although support was added in preparation for JSR-286, the latest release version of uPortal still uses JSR-168.
* Upgrades are non-trivial: Upgrades have been stated to be non-trivial and probably will run into things that are not-documented, but recently code was provided that should assist greatly in uP 2.5.3 and uP 2.6.1 upgrades to uPortal 3.x, and the community and developers are willing to assist.
* Configuration/Usage/Development may be more difficult: From what I read and hear from others, uPortal is just more difficult to use than Liferay, however there is much greater support from the uPortal community to help you through it.
* CAS is built-in. If you don't use CAS, it might not be as well-tested with your type of authN.
* Wiki documentation is sometimes out-of-date and lacking. They welcome anyone to assist with documentation that wants to help though.

Liferay

Pros

* Sun contributes to Liferay (Sun basically gave up with OpenPortal project and took on Liferay).
* The latest release version of Liferay uses the latest portlet spec JSR286.
* Default portal is pretty slick/feels polished: while the UI of uPortal quickstart has certainly greatly improved, Liferay's default version/skin/UI of the portal feels more polished. However, this probably doesn't mean much because you will end up needing to reskin it for your implementation.
* There is a project for those interested in developing portlets using JRuby on Rails (but it is Liferay and JSR-286 specific even though they welcome development to make it work with other portals): http://rails-portlet.rubyforge.org/
* There is a project for those interested in developing portlets using Grails (may be is Liferay specific and I think still only supports JSR-168): http://grails.org/plugin/portlets
* There are probably more portlets available in Liferay and I think they have more developers working on the project and more users, but am not sure.

Cons

* Community is less university/school focused
* CAS not built-in (if you are using CAS).
* Community/forums not nearly as helpful for universities or in-general as responsive at getting people up-to-speed (at least that is from what I hear. I can say for certain that the uPortal developers and community are very helpful.

Unsure

* Don't know anything about ease of Liferay upgrades.

Both uPortal and Liferay

Pros

* Both portals are Java-based: Integration with existing/new Java libraries is easier. Since Java has a very large userbase and there is a lot written in Java, you can develop portlets to do just about anything you can think of and reuse existing libraries from Apache/Jakarta, Sourceforge, Codehaus, Springsource, Hibernate, etc. along with plugins for Maven 2, tasks for Ant, etc.
* Both are standards-based and have active development and user communities.

Cons

* Portals in-general aren't as hot as they were years ago. There has been a lot of movement towards applications that make it easier to publish communication (Confluence/MediaWiki, Drupal/Joomla) or just in web applications that are faster to develop ((J/C)Ruby on Rails, etc.). However, there is still a place for them and the ability for users to customize them and what content they see is a great asset, and as long as you focus on continuing to provide things that the users actually want and need (even things outside of the institution's normal realm), the implementation will likely do well.

Wednesday, October 7, 2009

Should.not.equal vs. not should != with test_spec in Ruby

Found out today that a.should != b does not work in the version of test_spec (0.10.0) we were using in a project. Instead, you should use a.should.not.equal b or a.should.not == b.


>> "5".should.not.equal "2"
=> nil
>> "5".should != "2"
Test::Unit::AssertionFailedError: <"2"> expected but was
<"5">.
   from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/test/unit/assertions.rb:48:in `assert_block'
   from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/test/unit/assertions.rb:495:in `_wrap_assertion'
   from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/test/unit/assertions.rb:46:in `assert_block'
   from /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/test/unit/assertions.rb:83:in `assert_equal'
   from /path/to/my/project/vendor/gems/test-spec-0.10.0/lib/test/spec.rb:88:in `=='
   from (irb):16

Note that the successor of test/spec from Christian Neukirchen is called Bacon.

Testing/Implementing a Controller Method that Uses collection_select

Passing collection_select params via POST in a test and accessing those params can be a little bit tricky in Rails.

In the post (from the test) you must specify something like:


:parent_object_name => {:parent_attribute_object_id => some_id}
and then have to get it in the controller with:

params[:parent_object_name][:parent_attribute_object_id]

Let's say we have a model called Car that has a TireType attribute, and we want to use a collection_select (a select/dropdown box) to change it.

In the view, we create a select box with an associated button to make the change. Just for kicks, we also add a confirmation dialog:


    <% form_for TireType.new, :url => { :action => 'change_tire_type'} do |f| %>
      <%= collection_select(:car, :tire_type_id, TireType.all, :id, :name, {:prompt => true}) %>
      <%= submit_tag "Change Tire Type", :onclick => "return #{confirm_javascript_function('Are you sure you want to change the car\'s tire type?')}" %>
    <% end %>  

In the controller test (using test-spec just for this example):


context "anyone", ActionController::TestCase do
  use_controller CarController

...
  
  specify "should be able to change tire type" do
    new_tire_type = TireType.create!
    post :change_tire_type, :car_id => @car.id, :car => {:tire_type_id => new_tire_type.id}
    Car.find(@car.id).tire_type.id.should == new_tire_type.id
  end
end

And here is the method in the controller:


  def change_tire_type
    car = Car.find params[:car_id]
    tire_type_id = params[:car][:tire_type_id]
    new_tire_type = TireType.find(tire_type_id) 
    car.tire_type = new_tire_type
    car.save!
    redirect_to :action => :index
  end

Monday, October 5, 2009

Scaling Injection of Data via ActiveRecord in Initializers

ActiveRecord find_or_create is not (by default at least in Rails 2.3.3) an atomic operation on the DB, which means that if you have 4 servers doing a find_or_create for the same object at the same time, you're going to get anywhere between 1 and 4 records created. This is especially an issue in any initializers that might create data.

It would be interesting for Rails to go in and create find_or_create functions in the database, but it doesn't do that. And while you could use client-side transactions, as a general rule, you shouldn't.

So instead, an easy way to handle it is via enforcement of uniqueness of rows in the database via indexes. Here is a sample migration:


class EnsureUniqueViaIndexes < ActiveRecord::Migration
  def self.up
    add_index :apples, [:color], :unique => true, :name => 'unique_color_on_apple'
    add_index :cars, [:type, :year], :unique => true, :name => 'unique_type_and_year_on_car'    
  end

  def self.down
    remove_index :cars, [:type, :year]
    remove_index :apples, [:color]
  end
end

Then in the config/initializers/create_apples_and_cars.rb:


unless Apple.find_by_color('green')
  p "Creating green apple"
  begin
    Apple.create!(:name => 'green')
  rescue Exception => e
    p "Got exception during apple create. If is duplicate row, please ignore error(s)- is probably due to multiple servers hitting at once: #{e} #{e.backtrace}"
  end
end

# there happens to be default_scope of year on Car, so we only have to lookup by type
unless Car.find_by_type('compact')
  p "Creating compact car"
  begin
    Car.create!(:type => 'compact')
  rescue Exception => e
    p "Got exception during car create. If is duplicate row, please ignore error(s)- is probably due to multiple servers hitting at once: #{e} #{e.backtrace}"
  end
end

This way, you can get errors on the console, but it all works as expected with as little overhead as possible.