Final draft of my thesis.

CS299 Progress Report



Week 13

I've made some minor updates to the paper and RhinoFaces. Here is a status report for each piece.

Paper

I've reformatted this according to the thesis guidelines. They specify double spacing, which I am still ignoring. Otherwise, the remaining pieces:

  • Title page
  • Copyright page
  • Signature page
  • Abstract -- not sure if I should change my existing abstract into an introduction.
  • Table of contents

I added a paragraph to section 2, in a shameless bid to cite the remainder of my references. Here it is in its entirety.

Metaobject protocols have numerous applications, including persistence [11,13], pre/post conditions [14], tool support [5], and security [21], among others. Although CLOS is the most renowned metaobject protocol, other systems exist for different languages. Smalltalk, Ruby, and Groovy all include at least partial metaobject protocols, and several models have been proposed for Java [16].

I have not given the paper to my advisors yet, but it seems like it is close enough to final form to do so. After the meeting tomorrow, I will contact them.

RhinoFaces

I removed all of the extraneous classes and reduced the logging substantially. The MobileMusic application is working and demonstrates the key issues. This seems completed.

Things I would still like to do here:

  • Create a simple, example application (simpler and with less copyright issues than MobileMusic).
  • Create "getting started" documentation.
  • Try to submit this to Java.net or Codehaus.

JOMP

This is finished. I'm like to submit this to the Rhino mailing list and see what kind of response I get, but I'm planning to hold off until I can include some notes about RhinoFaces along with it.

My latest feature here has been a tracing example. This is also included as part of RhinoFaces.

Other

Besides these parts, I would still like to submit a portion of my thesis to be published. JOT seems like it still might be the best choice.

For the time being, this all seems secondary though. After the paper, it seems like my next tasks will be booking a room and getting my presentation together.

Week 12.5

This week I have a near-final draft of the paper, a near-final version of the RhinoFaces, a final version of JOMP, and a final version of MobileMusic (my sample RhinoFaces app).

In the paper, sections 6.3 and 7 have been heavily updated.

Remaining on the paper: I have a few sources in my references that I have not actually referenced. I don't think that will be hard to add. Also, I have not gone over the thesis format guidelines. I'm planning to do both tomorrow.

Remaining on RhinoFaces: The code needs a little cleanup, though I don't think it needs any new functionality. Also, I'd like to package up a sample application that someone could easily run. I'm going to work on the code cleanup tomorrow after the thesis draft.


Week 12

I've added functionality to the MOP to change the ids returned for enumeration and to alter the result of using the instanceof operator. I've used these along with the get functionality to implement multiple inheritance. That has been added to the end of the example page.

I've also added a unit test script and cleaned up the code in general. I'm going to freeze this piece now -- I could work on it forever, but I think it captures the key points that I wanted. I think my efforts now will be better spent on the write-up and RhinoFaces.


Week 11

I did not get a chance to update the write-up for RhinoFaces. However, I did successfully integrate my new version of the MOP into it.

I ran into one interesting issue: I had added some functions to the Object prototype. As a result of this, some of my functions broke because they were relying on being able to iterate through the object's fields. This was easy to fix, but it seems the ideal opportunity to override the JS getIDs function in my MOP. This could be set to return only fields that correspond to a column in the database.

Goals for this coming week:

  • Draft of writeup for JOT (or other journal).
  • Add getIDs MOP functionality. Integrate into RhinoRecord.
  • RhinoFaces writeup.
  • If time: add prototype and instanceOf MOP functionality. Use these along with getIDs to create multiple inheritance.

Week 10.5

I've rewritten sections 6 (all) and 7.2 of the paper. I still need to update the section on RhinoRecord, as well as RhinoRecord itself. My plan is to tackle that tomorrow. My references are still a mess, but I've kept adding to them, so I thought I'd clean them up at the end.

I read more about Ruby and its MOP. The consensus seems to be that it is a MOP, but an incomplete one. It passes the test because it has modifiable metaclasses. The only complaint is that it won't let you modify the syntax, which seems relatively trivial. Blocks seem like they can cover any case I could come up for when this would be useful.


Week 10

I've cleaned up the new design of the metaobject protocol and modified the example page to reflect the new setup. I've named the new version 'JOMP', for the JavaScript One-metaobject Metaobject Protocol. (I thought about 'ROMP' as well, but I did not want to tie it totally to Rhino.)

I've been copying JSAdapter's approach, except that my design is a true metaobject protocol -- the objects in the language really can be modified on the fly. By adding a __metaobject__ property to the language I believe the design is cleaner, more flexible, and more in the spirit of JavaScript than either JSAdapter or my original design.

Interestingly, this seems to have resolved the implementation bugs I had before. Perhaps I have traded them for newer, more wily bugs instead.

I have not yet integrated the new MOP into RhinoFaces. That will be my top priority for next week. After that, I'm going to rewrite the discussion of my implementation in my thesis report.

Week 9.5

I was able to find some more papers from ACM and IEEE through my SJSU library account. Also, I took a look at The Journal of Object Technology. The papers I am reading are:

  • Welch, Ian and Robert Stroud. Security and Aspects: A Metaobject Protocol Viewpoint.
  • Welch, Ian and Fan Lu. Policy-driven Reflective Enforcement of Security Policies.
  • Lee, Arthur H. and Joseph L Zachary. Reflections on Metaprogramming. IEEE Transactions on Software Engineering, November 1995, vol. 21, no. 11.
  • Denker, Marcus, Stéphane Ducasse, Andrian Lienhard, Philippe Marschall. Sub-Method Reflection. Journal of Object Technology, special issue TOOLS Europe 2007, October 2007, vol. 6, no. 9. http://www.jot.fm/issues/issue_2007_10/paper14/

I am coming to understand metaobject protocols better, and I am starting to wonder if my system really qualifies. It offers pretty much all of the same functionality, but it does not really have any metaobjects as such. In some ways Object and Function qualify, but I am not sure it is enough.

The true MOP approach would be to add a metafunction property to function. Whenever a function was used, it would call 'metafunction.invoke(func,args)', or something along those lines. The metafunction property could then be changed at will to alter behavior accordingly.

Really, even metafunction is not needed. By intercepting properties, we can wrap or replace functions easily. JavaScript's existing flexibility combined with this simple change provide just about all of the functionality that MOPs like CLOS offer.

But do my extensions really constitute a MOP, or is it something else?

I've been redoing my setup with a __metaobject__ property. So far, it seems to be going well. Here is an example:

      var mop = {};
      /**
       * Does not do much fancy...  Just logs
       * when the existence of a property is checked.
       */
      mop.has = function(thisObj,prop) {
        print("  **Calling MOP has " + prop);
        if (thisObj[prop]) return true;
        else return false;
      }
      /**
       * This returns a function that will call and object's
       * __propertyMissing__ function if a property does not exist.
       */
      mop.get = function(thisObj,prop) {
        if (prop == '__noSuchMethod__') return undefined; //Disabling Rhino's __noSuchMethod__.
        print("  **Calling MOP get " + prop);
        if (!thisObj[prop] && thisObj.__propertyMissing__) {
          return function() {
            thisObj.__propertyMissing__(prop);
          }
        }
        else return thisObj[prop];
      }
      /**
       * This just checks for a setter method before assigning a value
       * to any property
       */
      mop.set = function(thisObj,prop,value) {
        print("  **Calling MOP set " + prop + "=" + value);
        var setterName = 'set_' + prop;
        if (thisObj.hasOwnProperty(setterName)) {
          thisObj[setterName](value);
        }
        else thisObj[prop] = value;
      }

      //This will make this mop used for all objects.
      Object.prototype.__metaobject__ = mop;

      var father = {};
      father.__propertyMissing__ = function(prop) {
        print("No such property: " + prop);
      }

      father.hasOwnProperty('foo');
      father.foo();

      father.son = 'Cain';
      print(father.son);
      father.set_son = function(newSon) {
        print("++Calling setSon");
        this.son = newSon;
      }
      father.son = "Abel";
      print(father.son);
    

One nice addition is that I figured out how to disable the MOP within its definition, which makes designing the MOP much less complex. My plan for tomorrow is to try to port all of examples over to use this design instead.

One last interesting sidenote -- The latest version of Rhino now has __noSuchMethod__, which seems to be equivalent to Ruby's method_missing. I'll update my discussion on their features.


Week 9

I did not get a great deal done this week, but I found a few more promising references:

All 4 of these articles (plus the earlier article on Reflex) have versions on the ACM portal site (http://portal.acm.org). They seem to be the same articles, though I've been too cheap to pay the fee to find out.


Week 8

I've now updated my report to add section headers and page numbers, so hopefully it will be easier to refer to. The latest version is here.

I found a good paper about Self written by its designers. The paper is available at http://www.cs.ucsb.edu/~urs/oocsb/self/papers/self-power.html. JavaScript borrows both its prototype-based system and its nature of properties from Self, so the discussion seemed very relevant. I've mentioned self in sections 4.2 and 4.4.

I've added 'related work' as section 8. This includes my discussions about Mozilla JS, Java 6 JS, and PHP 5.

I still need to add some more references, but it may be time to switch back to the implementation. The only section where I don't have a preliminary version is of the music store sample application. I think working on that might also give me more inspiration about what else I need to cover in more depth in the paper.

Week 7.5

I've written up some analysis that I intend to add in my paper. I'm comparing my extensions with PHP, Mozilla's latest version of Rhino, and Sun's Java 6 Rhino implementation.

PHP 5 comparison

JavaScript and PHP have some striking similarities in their basic design. In particular, it is common in both languages to access properties directly. This is getting to be less true for PHP, but it is still far from unusual to see code like the following:

      echo user->full_name;
    

In contrast, you never access variables directly in Java or Ruby. It can be done, but is seen as something close to high treason.

A more important point is that both of these languages will accept new properties for existing objects. In Java, you cannot add a property to an object if it is not available for its class. In Ruby, you can do so through the use of singleton classes, but it is a much more complicated process.

Also, PHP does have the ability to intercept references to properties with its __get and __set methods. It is not as powerful as what I have proposed; it only catches properties that do not exist. However, this should still be enough to replicate method_missing.

Unfortunately for PHP developers, functions are not first class citizens in the language. Function references are never intercepted by __get or __set. Also, while you can make anonymous functions in PHP with 'create_function', these functions cannot be set as methods. This will fail:

      $emp->work = create_function('$beg,$end', 'echo "Work from " . $beg . " to " . $end;');
      $emp->work("9", "5");
    

The function is set as a property of $emp, but it is only a property. It can't be treated as a method. So while the above example fails, this will work:

      $emp->work = create_function('$beg,$end', 'echo "Work from " . $beg . " to " . $end;');
      $foo = $emp->work;
      $foo("9", "5");
    

In fairness to PHP, it does have a __call method which intercepts calls to unrecognized methods. However, because of its more complicated structure, it needs __get, __set, and __call to mimic the functionality of Ruby's method_missing. And unlike JavaScript and Ruby, it has no ability to add methods to an existing object.

By adding the methods getWildcardProperty and setWildcardProperty to JavaScript objects, we achieve the method_missing functionality, in addition to allowing a wide variety of other behavior. PHP's similar design nearly gives it the same possibilities, but it lacks the key element of JavaScript's first class functions.

Mozilla JavaScript getters and setters.

Mozilla has done some work on intercepting properties. Their description of this feature is here.

Unfortunately, their implementation is a little underwhelming. It does not offer any of the functionality of getWildcardProperty or setWildcardProperty. Furthermore, it does not even allow you to intercept the setting and getting of existing properties. This design loses many of the advantages of getters and setters.

The main focus of the change appears to be to allow FireFox JavaScript to interact with Microsoft specific JS code. While this is a major plus, it does seem that the designers were too narrowly focused on this one specific issue and missed a golden opportunity. To be fair, however, a more powerful design might have cost more in terms of performance. Perhaps that was their primary concern.

However, there is an interesting parallel to CLOS. One of the primary concerns of the CLOS designers was to smoothly interact with the various Lisp object systems that preceded it. They achieved this through a powerful MOP. In some ways, this is a similar problem to interacting with the different JS implementations of different browsers. Even with this limited addition to the language, the Mozilla team has given a powerful tool to developers to resolve this issue.

Java 6 JS

Java 6 has added support for scripting frameworks. As part of this, it includes a version of Mozilla's Rhino. For the most part, this is a somewhat watered-down version. It does not include support for continuations or e4x, for example. However, there is one interesting, almost entirely undocumented feature in Sun's implementation. This was brought to my attention by some of the Phobos developers after they saw my early research.

Sun's Java 6 version of Rhino includes a JSAdapter class, discussed here. This offers much of the same functionality as my proposed extensions, and actually includes a couple of additional features.

Instead of modifying the behavior of all objects in the language, this approach instead creates a special object with additional functionality. This object can be used to wrap other objects. When you attempt to get or set a property for this special object, it will call its __get__ or __put__ method, if one exists. Here is an example that will restrict access to the salary field (unless you refer to the emp object directly):

      var emp = {name:'Joe Bob Briggs', salary:5000}
      emp.__get__ = function(fieldName) {
        if (fieldName == 'salary') {
          throw new Error("Salary is restricted");
        }
        return this[fieldName];
      }

      var wrapper = new JSAdapter(emp);
      print("Reading details for employee '" + wrapper.name + "'.\n");
      try {
        print('Salary is ' + wrapper.salary); 
      }
      catch(e) {
        print(e.name + ": " + e.message);
      }
    

The JSAdapter objects also have __has__, __delete__, and __getIds__. While these functions seem much less useful, they effectively cover every way you access an object in JavaScript.

This approach does not include named interceptors, so this logic must be controlled by the __get__ and __put__ methods instead. Although this would be more difficult to use in the simple cases, it would be possible to implement named interceptors on top of __get__ and __put__.

Another disadvantage of this approach is the need for a special object. While this minimizes the change to the language, it also makes it more difficult to use this functionality within an object's constructor.

This manner of adding these extensions is very clever. However, it would be better to adapt the JS Object itself rather than relying on a new, special wrapper object. With this approach, we cannot truly modify an object's behavior itself at runtime, though we can come very close to it.


Week 7

I've updated the thesis draft, available here. Specifically, I've trimmed down the JSF section to a few paragraphs and finished the writeup of RhinoFaces and RhinoRecord.

I've signed myself up for a little more work in the paper. In one section, I talk about security applications of the extensions. My plan is to create a User constructor and a few additional functions. The goal is to provide an easier way to restrict access to different objects at a granular level. This will use just about every new MOP feature that I've added. I've added another example for this to the build.xml file, just to make sure that the concept seems feasible.

I have not spent any time yet polishing up the format, but that is next on my list. After that, I would like to write up a little more about Mozilla and Java 6 JS since they have some limited features to intercept properties. Also, I want to add a small section on CLOS, and do a little investigation into PHP.

PHP 5 has '__get' and '__set' methods that seem to basically work like my extensions. It also is very similar to JavaScript in its use of properties. However, functions are not nearly as powerful in PHP. I thought that contrasting these two languages would be a good illustration that intercepting properties is not enough by itself; JavaScript's core design is what really allows us to add all of this additional power with just some small changes.

The last section I intend to include is a discussion of a sample application built using JSF, RhinoFaces vanilla (no MOP features), and RhinoFaces with chocolate sprinkles (MOP features added). However, I think I need to get back to the sample application before I can really write this up.


Week 6

I've rewritten the conclusion and added a little about JSF and RhinoFaces. The new material starts on page 14. In particular, I'd like to make sure that my remarks on JSF are not off base. The latest draft of this paper is here.

I'm thinking about adding Tim Shadel's "7 Layer Burrito" podcast series to my list of references. It is obviously not an academic reference, but it does have a very in depth criticism of JSF. Also, I'm debating about adding CoreJSF, the JavaScript specification, and the JSF specification to my references. I've dug into all three, but I have not quoted any of them so far.

The biggest criticism of JSF (other than the configuration mess) has been the use of POSTs instead of GETs. Marc Chung has a page about how to do this in JSF. It seems like this might be a good feature to incorporate into RhinoFaces, especially since he already has written the code. It would be nice to have pretty urls, like 'album/surf_cinema', but even a bookmark-able 'album/view.faces?id=3' would be an improvement. (For the record, both Rails and Grails have good tools for pretty urls.)

Outside of research and writing, I've done a little housecleaning for the framework. A number of utility scripts, most importantly RhinoRecord, are now loaded when a new session starts. This gets rid of some embarrassing full path references to those files.

Week 5.5

Last slide

Here is the planned last slide of my presentation.

Conclusion and Achievements

  1. I have modified the Rhino implementation of JavaScript to intercept the setting and getting of properties. In doing so, I’ve added many metaprogramming features to the language.
  2. I have built a web framework with much of the ease of use of Ruby on Rails, but backed by the power of Java and JavaServer Faces. This illustrates how these extended features may be useful in building more intuitive, more flexible, and more secure APIs.
  3. I have built the same web application using JavaServer Faces, RhinoFaces, and RhinoFaces with the extended metaobject protocol features. This shows how these features make the programmer’s job easier.

Outline

This is the outline for my thesis. New sections are in red. Sections I may delete are crossed out.

  1. Introduction
  2. Metaprogramming and Metaobject Protocol overview
    1. CLOS
  3. Ruby overview
    1. Object-oriented design
    2. Type System
    3. Ruby on Rails
    4. Metaprogramming
  4. JavaScript overview
    1. Rhino
    2. Prototype-based object design
    3. First-class functions
    4. Properties
  5. Metaprogramming: Ruby vs. JavaScript
    1. Singleton classes
    2. Eval methods
    3. Aliasing a method
    4. Callable objects
    5. Mix-ins
    6. Callbacks and hooks
  6. JavaScript Metaobject Protocol Proposal
    1. Mix-ins
    2. Property Interceptors
    3. Applications of the new extensions
    4. Implementation
    5. Related work
      1. Mozilla implementations
      2. Java 6 JS implementation
  7. RhinoFaces proof of concept
    1. JavaServer Faces
      1. Components
      2. Criticisms
      3. Contrast with Rails
    2. Goals of framework
      1. Minimal configuration
      2. Allows fallback to Java
      3. Easy database access
    3. RhinoRecord
    4. Navigation
    5. Automatic loading of backing beans
    6. Scope
    7. MobileMusic -- Sample application
      1. Pure JSF version
      2. RhinoFaces, sans metaprogramming extensions
      3. RhinoFaces, full featured
  8. Conclusion

List of references

  1. Rivard, Fred. Smalltalk: a reflective language. (Accessed November 2006). http://www2.parc.com/csl/groups/sda/projects/reflection96/docs/rivard/rivard.html.
  2. Paepcke, Andreas. User­level crafting introducing the CLOS metaobject protocol. (Accessed December 2006). http://infolab.stanford.edu/~paepcke/shared­documents/mopintro.ps.
  3. Tanter, Éric, Noury M. N. Bouraqadi­Saadani, and Jacques Noyé. Reflex – towards an open reflective extension of Java. (Accessed December 2006). http://www.dcc.uchile.cl/~etanter/research/publi/2001/tanterBouraqadiNoye-reflection2001.pdf.
  4. Kiczales, Gregor, Jim des Rivières, and Daniel G. Bobrow. The art of the metaobject protocol. MIT Press, 1991.
  5. Kidd, Eric. Why Ruby is an acceptable Lisp. (Accessed April 2007). http://www.randomhacks.net/articles/2005/12/03/why-ruby-is-an-acceptable-lisp.
  6. Yegge, Steve. Lisp is not an acceptable Lisp. (Accessed April 2007). http://steve-yegge.blogspot.com/2006/04/lisp-is-not-acceptable-lisp.html.
  7. Tate, Bruce. Beyond Java. O'Reilly Media Inc. 2005.
  8. Flanagan, David. JavaScript: the definitive guide, 5th ed. O'Reilly Media Inc. 2006.
  9. Black, David. Ruby for Rails. Manning Publications Co. 2006.
  10. Crockford, Douglas. The JavaScript Programming Language. Yahoo presentation. (Accessed May 2007). http://yuiblog.com/blog/2007/01/24/video-crockford-tjpl/.
  11. Crockford, Douglas. JSLint: The JavaScript Verifier. (Accessed April 2007). http://www.jslint.com/lint.html.
  12. Matsumoto, Yukihiro. Ruby’s Lisp features. Ruby-talk mailing list archives. (Accessed May 2007). http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/179642.
  13. Hertel, Matthias. Cross Browser JavaScript. http://www.codeproject.com/jscript/crossbrowserjavascript.asp. (Accessed August 2006).

Week 5

SUCCESS!!!   SUCCESS!!!   SUCCESS!!!

My Rhino JavaScript modifications have been successfully integrated into RhinoFaces. The resulting code is much more concise.

First, let's look at the original JavaScript code for the JukeBox backing bean. This was already a substantial improvement over the Java version:

      function JukeBox() {
        this.albums = new Array();
        this.artists = new Array();
        this.songs = Song.findAll({orderByDesc: 'numDownloads'});
        this.currentAlbum = null;

        var iter = this.songs.iterator();
        while (iter.hasNext()) {
          var tempSong = iter.next();
          if (!this.albums[tempSong.albumId]) {
            var album = Album.findFirst({id: tempSong.albumId});
            album.songs = new ArrayList();
            this.albums[tempSong.albumId] = album;

            if (!this.artists[album.artistId]) {
              var artist = Artist.findFirst({id: album.artistId});
              artist.albums = new ArrayList();
              this.artists[album.artistId] = artist;
            }
            album.artist = this.artists[album.artistId];
            album.artist.albums.add(album);
          }
          tempSong.album = this.albums[tempSong.albumId];
          tempSong.album.songs.add(tempSong);
        }

        this.currentAlbum = this.albums[1];
      }
    

The new version uses the more advanced features of RhinoRecord. These features rely on the MOP extensions I've added, and the end result is much leaner code:

      function JukeBox() {
        this.songs = Song.findAll({orderByDesc: 'numDownloads'});
        this.currentAlbum = this.songs.get(0).album;
      }
    

To be fair, the code is not exactly equivalent. The first version also initializes this.albums and this.artists, which could be useful. We could, of course, do this with Album.findAll() and Artist.findAll(). But as it turns out, this is not something we need so far in the application. And eliminating this.albums and this.artists would not have saved any lines of code from the original. 2 collections would still have been needed to track which albums and artists had been loaded already.

Another difference is that most of the associations have not been established by the time this bean has been loaded. These are handled in a lazy manner -- until you ask for it the first time, it is not set up.

The framework could still use some polish here and there, but the last major promised feature for the framework has been completed.

Remaining tasks

My primary goal now is to begin work on the paper. I'm going to add a section about Lisp's CLOS and some of the goals for its design. Also, I'm going to write in depth about both RhinoRecord and RhinoFaces. RhinoRecord will give me an excellent chance to demonstrate how manageWildcardProperty can be used, and some of the risks that it entails.

Outside of that, my first goal is to polish and package up the framework so I can have folks begin testing it for me. Given the time constraints of those I intend to enlist, quick setup and clear instructions are essential. (This is, I think, one of the major advantages of Grails over Phobos -- it is a heck of a lot easier to get started in Grails. For a nascent framework, this makes all the difference.)

After that has been done, I'll start extending my music store example. I intend to add a login, the ability to purchase songs, and possibly a maintenance page. Also, I'll follow suit with a vanilla JSF app so that I can contrast the 2 versions.

But for now, my primary focus will be on the writeup.

Week 4.5

So far this week, I have fixed my ActionListener class and added flash scope to the application.

Fixing ActionListener

The biggest ugliness in my implementation was that I was catching an exception to determine the name of functions to call within my ActionListener class. This has been fixed now. Instead, it will parse the action string to determine if it is a method call are not. If it is, it will pass the string to the JavaScript environment

The only possible downside is that this now takes precedence over Java calls. If the method is not available in the JavaScript environment, it **should** defer to the default ActionListener and call the appropriate Java class. However, this has not been tested.

Adding flash scope

I've made 'flash' a reserved variable within RhinoFaces. When the JavaScriptEnvironment class is first initialized, it makes this call:

      var flash = {};
    

After that, anytime that a view is rendered, it follows this up by "flash = {};". When a call is made to a missing property (e.g. flash.noSuchProp), "UNDEFINED" is replaced by an empty String. This seems to have exactly the desired effect -- no variable in the flash survives after one page view.

Problems delegating to ApplicationImpl

I spent some effort attempting to remove all references to the reference implementation classes. Unfortunately, I still cannot get RhinoApplication to delegate to the reference implementation's ApplicationImpl class.

It appears that ApplicationImpl cannot be instantiated in a different ApplicationFactory. I attempted to do this in RhinoApplication directly, within RhinoApplicationFactory's initialization, and even the getApplication call to RhinoApplicationFactory. Either it would get into an infinite loop or complain that the application had been initialized already.

I may take another crack at this later. It does seem that JSF itself has this type of modularity. (I was able to determine the default Application implementation by using the FactoryFinder class.) However, for now I'm going to leave RhinoApplication extending ApplicationImpl instead.


Week 4

The second 'half' of this week was just a day, but anyway... I've focused on RhinoRecord for today.

I've added findBy* functionality to RhinoRecord as well as dynamically associating managed objects with each other. Both use the new MOP features I have added to the language. Unlike with Rails, these associations do not need to be added to the code -- they are determined automatically. The downside is that there is no equivalent of 'has_one' or 'has_and_belongs_to_many', but this seems like a fair trade.

I've made it possible to disable these features, in case anyone wants to use RhinoRecord without my modified version of JS. Also, I've set the db properties to be a configurable part of RhinoRecord. A new script would configure RhinoRecord like so:

      load('/rhinoRecord.js');

      RhinoRecord.db.jdbcUrl = "jdbc:mysql://localhost:3306/mobilemusic_development";
      RhinoRecord.db.jdbcUser = "root";
      RhinoRecord.db.jdbcPassword = "";
      RhinoRecord.db.jdbcDriver = "com.mysql.jdbc.Driver";
      
      RhinoRecord.enableMop = true;

      eval(manageRecord("Song"));

      var songs = Song.findAll({orderByDesc: 'numDownloads'});
    

I'm still using eval a few places like this for expedience, which should probably be cleaned up, but it seems like a low priority for the time being.

I now have managed to put the full set of features into RhinoRecord that I had promised to include. While I expect I may need to add some new features or do some fixes, this piece seems to be more or less completed. The (maybe) final version of RhinoRecord is here.

I still need to integrate the advanced MOP features of RhinoRecord into RhinoFaces. At the moment this is causing a NullPointerException somewhere in the bowels of the modified Mozilla code. I have not tracked down the source of this yet, but it seems like it is only a matter of time.

One interesting problem I ran into on RhinoRecord: properties referred to in getWildcardProperties are still managed by getWildcardProperties. While I have some protections against this, it is still possible to get into an infinite loop. Here is the offending code:

        RhinoRecord.prototype.getWildcardProperty = function(propName) {
          if (this[propName]) return this[propName];
          
          // Offending line below
          if (this.has[propName + 'Id']) {
            var constr = eval(RhinoRecord.capitalize(propName));
            this[propName] = constr.findFirst({id: this[propName+'Id']});
            return this[propName];
          }
          if (propName.match(/s$/)) {
            var constr = eval(RhinoRecord.calcConstrNameFromPlural(propName));
            if (constr) {
              var options = {};
              options.params = {};
              options.params[this.tableName.slice(0,this.tableName.length-1)+'Id'] = this.id;
              this[propName] = constr.findAll(options);
              return this[propName];
            }
          }

          return undefined;
        }
    

The problem is that `this[propName+'Id']` also results in a call to this function. So when I was looking for 'albums', it first checked for 'albumsId', which did not exist. So it then checked for 'albumsIdId', and then 'albumsIdIdId', and so on.

The fix was simple enough: this.hasOwnProperty(propName + 'Id')

Week 3.5

So far this week, I have researched conversational scope and added functionality to automatically load backing beans.

Backing bean scripts

Now, when an unrecognized variable is called, RhinoFaces will look for a script with the same name as the base portion of the url. For instance, when going to 'cart/viewCart.faces', if no 'cart' variable exists in the JavaScript environment, it will look for 'cart.js'. If that is found, it will load the script.

Once the script has loaded, it will call "var cart = new Cart();". It does do some checking first to make sure that the variable does not already exist and that the constructor does exist.

Conversation scope

Conversation scope is designed to allow multiple tabs to be opened within the same conversation flow (but different instances), but without relegating them to separate sessions.

For example, using the Java quiz example from Core JSF, conversational scope would allow 2 different tabs to have different instances of the quiz. However, if you wished to display the combined score of both games, that information could be stored in the session, and both instances could make use of it.

Apparently, the way that Seam implements this is by adding a conversation ID parameter to the url of each request. This is done by using a filter.

RhinoApplication issue

One issue with this class is that it is tied to Sun's reference implementation. It extends com.sun.faces.application.ApplicationImpl. While this works, it does not seem like the best approach. For one thing, it would probably cause issues for anyone attempting to use this on JBoss or another implementation.

For every other piece, I've gotten around this by using the delegation pattern. This works well, and I'd like to do the same here. The problem is that I'm not sure how to get the default implementation to make it a delegate.


Week 3

This week I made some improvements to RhinoRecord and made some adjustments to the webapp. I've also integrated the modifed version of JS into RhinoFaces, though without the extra features working just yet.

Ruby-type behavior for properties

I had mentioned this earlier, and I decided to see if it was possible to make calling a JavaScript function indistinguishable from referring to a property. While this would generally not be a good thing, within the context of interpreting a JSP page, it could simplify the process.

Here is a brief example. This script has been uploaded to my server, and the new build.xml file has a 'ruby-props' target that will run it.

      var t = {};
      t.firstName = "Bill";
      t.mi = "E";
      t.lastName = "Boyd";

      //These functions will be treated as properties
      t.nickName = function() { return "Bubba"; }
      t.fullName = function() { return this.firstName + " " + this.mi + ". " + this.lastName; }

      t.getWildcardProperty = function(propName) {
         if ((typeof this[propName]) == 'function') {
            return this[propName]();
         }
         else return this[propName];
      }
      t.manageWildcardProperty();

      print(t.firstName + "'s full name is " + t.fullName + ", but his friends know him as " + t.nickName);
    

Intercepting properties

The modified JS jar file has been swapped into RhinoFaces. Properties can be intercepted, but RhinoFaces trying to interpret the result causes an exception to be thrown. I need to do some work here.

The main areas where I want to be able to use this feature:

  • Implement find_by_* feature of ActiveRecord
  • Create associations between classes automatically. (belongs_to and has_many functionality from AR)

JSF backing beans

I've held off on trying to rearchitect my design for now. It sounds like the central goal is to easily load new java backing beans (or their js equivalents).

In the existing implementation of RhinoFaces, application.js largely takes the place of faces-config.xml. Instead of wiring up a controller bean in the XML, I have 'var controller = new Controller()' at the end of the JS (or whatever bean I am trying to create.) Likewise, loading additional class information is done by using load() calls at the top of the page.

The question seems to be if more can be done than just swapping out XML with JavaScript.

The Rails approach is 'sensible defaults'. In keeping with that philosophy, but staying more in line with JSF's architecture, perhaps this would be a better approach:

First, load application.js at the start of the session. This would allow you to override or ignore any defaults. While it could be abused, the flexibility seems like a good trade.

If #{foo} is called from one of the JSP pages, it would need to be looked for in the JS environment. If there is no 'foo' variable, the next step would be to look for a 'Foo' constructor function to create a new 'foo' instance. If there was no constructor either, it could then look for 'foo.js'.

This design would give a fair amount of flexibility. However, if the convention of putting the backing bean constructor for 'Foo' in 'foo.js' were followed, it would make the programmer's life much easier.

Week 2.5

So far this week I have been planning a more detailed structure for the framework. In order to make RhinoFaces more flexible and at the same time more organized, I'm planning to add some more (optional) structure. Following the Rails philosophy, the conventions won't be enforced, but will make life easier if you follow them.

Controllers

One of the big changes will be to add multiple controllers. The main controller will be left in application.js, and it will remain in session scope. However, if the urls have two levels (like Rails apps do), the first will specify the controller and the second will determine the action. So '/album/preview' will look for 'albumController.js', where it will look for 'function AlbumController()'. If found, it will create a new instance and call the preview method on that instance.

However, unlike Rails, this controller will be stored in the session. Although different controllers won't know about each other, they can communicate through the controller from application.js.

This gives RhinoFaces controllers conversation scope, effectively, if the conversation is limited to a single controller. To further give this effect, I'll add an 'endConversation()' method that will remove the controller from the session. This will cause a new controller to be created the next time these pages are loaded.

This plan requires that variables can be passed between JS environments. This should not be a problem, but might require some inventiveness.

Other files

The Rails convention is to have an app/ directory that contains models/, views/, controllers/, and helpers/. This is not a bad setup, and I think in makes sense for RhinoFaces to follow that. The ant build file could then be used to put the files in the proper places for the warfile.

In the case of RhinoFaces, a place should be made for the java files too, so the app/ directory will have models/, views/, controllers/, utils/ (because I never like the name 'helpers'), and java/.

Navigation

One notable patch of ugliness in the RhinoFaces code is the method of navigation. It attempts to navigate normally and if that fails, it then navigates to a page with the same url as the action.

The fallback functionality is nice. It means that an existing JSF app can be used as-is with RhinoFaces. However, the fallback is done by catching an exception and parsing the stacktrace for the name.

There has to be some way that the ActionListener can tell what page was requested, and if faces-config.xml can handle the request. At the moment, the only clean solution seems to be to rewrite the functionality of the ActionListener totally.

Until I can determine a better approach, I'll live with the ugliness.


Week 2

This week, I got the navigation working for both the JSF and RhinoFaces versions of the application. The RhinoFaces version is fully caught up in terms of features. The dataTable component works as you would expect.

More thoughts on RhinoFaces's current design

In RhinoFaces, the controller is the JS environment. This seems to work well, though it does require some discipline. Rails shoves you down the path of organized code. So far, RhinoFaces really does not. You do not need to create any classes, or even any functions for that matter. This is really more the PHP way than the Rails way.

However, it does enforce a separation between view and model/controller, and more so than Rails does.

A controller is created once per session. At this point I am happy with that. However, request-scope controllers might make the development process more dynamic. Currently, the project must be redeployed for the rhino changes to be reflected. (Presumably expiring the session would work too, but I have not tested that.)

RhinoFaces's TODOs

There are a few issues with the current design. These are not really pressing at the moment, but should be fixed at some point.

  • 'load' statements within the rhino files require absolute paths.
  • DB properties are hardcoded in rhinoRecord.js. These should at least be moved to a separate js file.
  • The RhinoActionListener class is an abomination unto mankind. If there is any way to clean it up, it should be cleaned up. (However, in the past I had little luck finding the hooks I needed into JSF.)

MOP extensions

This week I ran into several areas where changing the behavior of JS would be beneficial. All (I believe) would be possible with my proposed MOP extensions.

  1. Add ActiveRecord's "has_many" and "belongs_to" features.
  2. Add find_by_* feature from AR.
  3. Simplify calling Rhino methods from within JSF.

The last issue ties back to a fundamental difference between Ruby and JavaScript. In Ruby, properties and method calls are indistinguishable. In contrast, JavaScript stores methods as properties.

JavaScript's treatment of methods is often preferable; it makes several metaprogramming techniques simpler. However, when working with JSF to get values, it would make the job easier if we did not have that distinction. For example, we might have this in one of our jsp pages:

      <h:outputLink value='#{jukebox.randomSong.url}'>
    

When we are in a JSP page, we will almost never be looking to get the function itself. We really do not care whether randomSong is a method. We could get around this issue with reflection, and in many cases that is probably the better approach. However, with the new MOP features, we can instead change the way that JavaScript properties behave within a given context. Metaobject protocols are really designed to offer just this kind of power.

Week 1.5

Scope in Ruby on Rails

In JSF, each bean's scope is configured manually in faces-config.xml. This is classic JSF -- a flexible solution requiring (arguably) excessive configuration for most cases.

Rails takes a different approach. By default, almost everything in Rails is request scope. The only exceptions seem to be the flash and session maps. Variables can be stored in the flash and will be available for the following request to use, but will be unavailable afterwards. As you would expect, variables in the session map are available for that session only.

There seems to be no exact equivalent of application scope. Class variables seem to have this scope, but only when Rails is in production mode. This strongly suggests that this is done only for performance reasons. It is probably unwise to rely on it.

Is this a flaw in Rails? It seems hard to think of a case where application scope variables would be useful, at least for most typical web applications. For those situations where it does occur, the Rails-y thing to do would be to put it in the database.

Scope in RhinoFaces (currently)

RhinoFaces currently takes the middleground between these two approaches. It stores the JavaScript environment in the session, so that the environment is available for all of that session's requests. This does mean that the developer will need to consider multiple requests more carefully. On the plus side, it makes tools like the flash very easy to emulate. (This might actually be a good use of the extended metaprogramming features -- The flash object could be set to return an empty string for any unrecognized properties.)

One advantage of RhinoFaces is that application or request scope variables could still be used by creating new java beans and configuring them in faces-config.xml. They could access the JS environments then through the session if they needed to.

Variables in Rails and RhinoFaces

In Rails, when a request is made a new controller is created. A method from the controller will be called. This is determined by the url, so that '/music_corner/latest_hits' will call the latest_hits method from the new instance of MusicCornerController. (Like all things in Rails, this default can be overridden. '/top-funky-tunes' could be mapped to MusicCornerController.latest_hits if desired.)

The variables available within the page are all of the instance variables for the controller. (This requires use of Ruby's MOP to open up the controller -- the variables would otherwise be unavailable without getters/setters.) Local variables within the method are not visible.

In contrast, RhinoFaces's scripts are all loaded at the beginning of a session. JSF references to variables are converted into JS calls, like so:

  • #{album.firstSong} ==> album.firstSong;
  • #{controller.answerAction} ==> controller.answerAction();

This means that there must be variables named 'album' and 'controller' in the scripts. RhinoFaces treats actions as method calls to the JSEnvironment. Otherwise, method calls are not available with the pages. (This could be fixed with the MOP extensions -- properties could be set to trigger a method call and return the result.)

Should RhinoFaces Use Request Scope?

This might not be too bad of a change to make. Emulating Rails, 'session' and 'flash' maps could be added that would persist (and perhaps an 'application' map as well), and the controller could be recreated each session. In contrast to Rails, JSF seems designed to expect only a single controller, so this might simplify the job.


Week 1

This week, I have begun a sample music store application in JSF and RhinoFaces. (I have an existing version in Rails already). In addition, I have been exploring Lisp and its macro design more. This is a precursor to diving more into CLOS.

JSF implementation

So far, there are only two pages in this web application. There is a main page that lists the available songs. There is a link to listen to an excerpt for each song and a link to a page for the album. (There are also other, non-functioning links at the moment). The data is stored in a MySQL database.

I ran into one major issue. I could not figure out how to make each link refer to a unique album page. One possibility would seem to be to use h:outputLink and build the url to include the id of the album. This is getting very PHPish though.

Using h:commandLink seems like it is the proper way, but I can't figure out how to make this work either. For the time being, I have swept this under the rug. The album page currently always loads the first album in the database.

There are some other, less urgent TODOs here:

  • Add pages for all broken links.
  • Move out common html chunks (maybe using Tiles?).
  • Move the DB configuration info out of the source code.

RhinoFaces Implementation

I attempted to convert over what I had for the JSF version to use RhinoFaces instead, but it did not work. I was successfully able to include RhinoRecord, but components don't work yet.

I had tried to use a dataTable like I did in the JSF example. Unfortunately, the JS environment does not recognize the variable created when iterating over the collection.





CS297 Progress Report


Final Week

This week I completed the report and finished the Rhino implementation. The build.xml default task will download the latest jar and run some examples. 'ant run' will rerun the script without downloading the jarfile.

There is an issue with the implementation. Its managed properties do not carry over to any clones, which is a problem. Nonetheless, this does allow for the ability to test all of the features.

Week Thirteen

This week I focused on my writeup. The latest version is available here.


Week Twelve

Tasks done this week:

  • Began write-up of paper
  • Hacked Rhino to intercept the setting of properties
  • Wrote a more complex RhinoRecord script (which also populates the data for the sample web application)
  • Created a page to begin cataloging some of Rails features

Some issues:

  • Not sure what the style guidelines are for the paper

Rhino property setter

To intercept properties in Rhino, I've added a map of properties to methods in ScriptableObject.java. This works for both JavaScript and Java objects. So far, I have not done more that hardcode a single property interceptor for 'foo', which looks for the 'setFoo' property in the same context, but it illustrates the concept. Here is a script using the modified version of rhino:

      //Sample script that shows a normal property and a watched property (foo) being set.
      var t = {};
      t.name = "tom";
      print(t.name); //This will just print "tom"
      
      t.setFoo = function(val) {
         print("Heya.  In setFoo");
         this.foo = val + "!!!";
      }
      t.foo = "yay"; //This results in a call to t.setFoo()
      print(t.foo);

      t.foo += "add this at the end";  //So does this
      print(t.foo);
   

You can download and test this by running the same build.xml file from week one. The test.js script has been changed to the above. 'ant' will download the modified jar and run the test script. 'ant run' will rerun the script sans the download.

I have not determined the syntax that should be used for this yet. This is what would seem ideal:

      this.foo.intercept = function(foo) {
         print("Setting foo");
         this.foo = foo;
      }
   

The problem is that this would be incompatible with any scripts that already have an intercept property. Maybe this is acceptable.

Rhino is built to allow custom functions to be added to the language, although it requires a modified Scope object to do so. (Rhino has layers and layers of these classes to give the scripts access to more non-standard JS utility functions, so this is not really a big issue.) Taking that approach would give the less pretty, but more Rhino-ish:

      addPropertyInterceptor(this.foo, function(foo) {
         print("Setting foo");
         this.foo = foo;
      });
   

I have not attempted to use this for improving RhinoRecord yet. That might make it clearer which approach is better.

RhinoRecord update

Rhino is the handiest tool there is for scraping a website. The Hpricott Ruby library is not bad, but still comes short compared to Rhino's built-in readUrl() function.

For this week, I wrote a script to scrape a number of pages from the music site cdbaby.com. It will download information, mp3s, and album covers. After it has done so, it will write this information to the database. This script requires a new version of RhinoRecord.

The associations are all done automatically, though they are only one way. Since a song has an 'album' property and it has an 'album_id' field in the database, it can tie together this information itself. It should be possible programmatically to determine the association the other way as well, and add a 'songs' property to each album object.

The main downside of this is that there is no way to distinguish between has_many and has_one. Is this a major limitation? Why doesn't Rails default these associations? It seems to have all of the knowledge it needs.


Week Eleven

Tasks done this week:

  • Fixed JS environment to use Rhino's extra functions
  • Set RhinoFaces to load only application.js or application.rhino
  • Added support for 'load()' function. Scripts are relative to the application.(js|rhino) script
  • Updated RhinoRecord
  • Loaded RhinoRecord within JSF

JS Environment

There are multiple levels of Scriptable objects. Each layer seems to add a few more functions. "Scriptable" gives just the standard set of ECMA JS functions. The "Global" class seems to include all of the additional functions needed to script java.

I also changed the way that the scripts are loaded. Now, the process looks for application.js on the classpath (or alternately application.rhino). This follows the convention Ruby on Rails uses for its central controller class.

One problem I ran into was that the "load" function needed absolute paths. Relative paths would be from the directory where the application was running. To fix this, I extended the Global class and overrode the "load" method to use relative paths. All other scripts will be loaded from the path relative so the application script. In other words, if no path is specified, it will look for the specified script in the same directory as application.js. Absolute paths still work the same as they do today.

Ideally, each script's call to load() should be relative to itself. However, the current setup will be good enough for now.

The same should probably be done for the loadClass function as well.

The trouble with JavaScript

JavaScript, by convention as least, does not make use of getters and setters. This is unfortunate, because it causes some problems when trying to write an ActiveRecord implementation in the language.

A key feature not implemented in my version is the associations. ActiveRecord allows developers to associate two objects by specifying has_one, has_many, belongs_to, etc. So, for example, here is the source for 2 related models:

      # In album.rb
      class Album < ActiveRecord::Base
        belongs_to :artist
        has_many :songs
      end
      
      # In artist.rb
      class Artist < ActiveRecord::Base
        has_many :albums
      end
   

The associations actually add setters and getters to the language. The result is that setting the association only needs to be done one way to set it for both. Here is an example:

      mark_growden = Artist.new
      mark_growden.name = "Mark Growden"

      live_at_the_odeon = Album.new
      live_at_the_odeon.artist = mark_growden
      live_at_the_odeon.title = "Live at the Odeon"

      live_at_the_odeon.save()

      puts live_at_the_odeon.artist.name
      puts mark_growden.albums[0].title
   

This prints:

      Mark Growden
      Live at the Odeon
   

A logical way to do this would be to add extra logic to the setter methods, but without breaking the convention (and complicating the JSF ELResolver logic) this does not seem to be possible in standard JavaScript. There are a few different approaches that might be workable:

  1. Add a property listener
  2. Make the object a java bean
  3. Only save the associations once they hit the database

The first approach would seem to be a good choice, except I'm not sure that such a thing exists. Damned reality.

This works, but is not flexible enough. By having the JS object implement a Java interface, you can add any getters that you like. Any call to album.artist could be set to call album.getArtist() behind the scenes. The same could probably be done for setter methods if they were in the interface. This does not matter much. I need to be able to add arbitrary setter methods that will be called whenever the property is set. In Rhino, attempting this causes an exception to be thrown.

The last approach seems complicated and kludgy... except that it appears to be what ActiveRecord actually does. The example Ruby code above would not work without the call to 'live_at_the_odeon.save()'.

I may be making an issue out of nothing. Still, the JS convention of referring to a property directly does seem potentially problematic.

Can Rails scale?

This has been a common criticism of Rails. For the most part, the Rails community has been dismissive of this claim. However, it seems that there is a site that is putting Rails's scalability to the test.

Twitter is one of the largest Ruby on Rails sites currently out there. John Kenzer interviewed Alex Payne, one of Twitter's lead developers. He had a few negative comments:

Running on Rails has forced us to deal with scaling issues ... far sooner than I think we would on another framework.

Once you hit a certain threshold of traffic, either you need to strip out all the costly neat stuff that Rails does for you ... or move the slow parts of your application out of Rails, or both.

David Heinemeier Hansson's response comes across as more than a little defensive, and perhaps a touch arrogant. The central point stands, however. Currently, scalability does appear to be a problem for Rails.

Rails Console

One neat feature of Rails is the console. This allows you to investigate your models and make changes on the fly. Here is an example where I add a new record to the songs table:

      $ ruby script/console 
      Loading development environment.
      >> s = Song.find_by_name "The Island"
      => #"42", "name"=>"The Island", "genre_id"=>"7", "album_id"=>"1", "duration_in_seconds"=>"120", "id"=>"3", "file"=>"namelyus-theisland.mp3"}>
      >> s.album.title
      => "Namely Us"
      >> song = Song.new
      => #0, "name"=>"", "genre_id"=>0, "album_id"=>0, "duration_in_seconds"=>0, "file"=>""}, @new_record=true>
      >> song.name = "Trouble" 
      => "Trouble"
      >> genre = Genre.find_by_name "Folk"
      => #"Folk", "id"=>"6"}>
      >> song.genre = genre
      => #"Folk", "id"=>"6"}>
      >> odeon = Album.find_by_title("Live at the Odeon")
      => #"2", "price"=>nil, "title"=>"Live at the Odeon", "url"=>nil, "id"=>"2"}>
      >> song.album = odeon
      => #"2", "price"=>nil, "title"=>"Live at the Odeon", "url"=>nil, "id"=>"2"}>
      >> song     
      => #0, "name"=>"Trouble", "genre_id"=>6, "album_id"=>2, "duration_in_seconds"=>0, "file"=>""}, @album=#"2", "price"=>nil, "title"=>"Live at the Odeon", "url"=>nil, "id"=>"2"}>, @genre=#"Folk", "id"=>"6"}>, @new_record=true>
      >> song.save
      => true
      >> quit
   

This can be a handy way to troubleshoot. Although it is mostly used for investigating models, it can also be used to load a session and investigate it.

RhinoRecord (previously DynaRecord)

This was updated in several ways. First of all, a findAll() method has been added. Secondly, the boilerplate code to initialize a record has been moved away. This was done using eval, which leads to the terse (albeit bizarre) setup for a new record:

      eval(manageRecord("Song"));
   

This replaces the previous version:

      function Song(props) {
         this.superclass = RhinoRecord;
         this.superclass(arguments.callee, props);
      }
      Song.prototype = new RhinoRecord();
      Song.prototype.constructor = Song;
      new Song();
   

RhinoRecord has successfully been loaded inside of a JSF application. However, it is not actually driving the application yet.


Week Ten

Tasks done this week:

  • Improved navigation
  • Began a sample web application in PHP, Rails, and RhinoFaces

Some issues:

  • There are problems calling java objects from the embedded Rhino environment
  • I have not made any progress with the MethodExpressions

Navigation

The application will now attempt to navigate normally first. If still on the same page, it will attempt to go to a jsp page with the same name as the outcome.

This allows the developer to use a mix of configured navigation rules and defaults. However, there are two problems with this approach. First of all, the developer might have intended for the user to remain on the current page. Secondly, the default jsp page might not exist. If it doesn't, the application crashes.

With the navigation handler, there is no way to tell what navigation rules exist. Likewise, there is no way to tell if the navigation succeeded or not. All you know is if the page changed.

The only solution I can see is to read in faces-config.xml and re-parse it. Also, you would need to scan for existing jsp files so that you would know which outcomes do not translate to jsps. It seems like there should be a better way.

However, for now it seems like it is working well enough. I'd like to put it on the back-burner for the time being and work on more pressing issues.

Sample Web App

This week I began work on a sample application using RhinoFaces. I am doing MobileMusic, an online music store. For kicks, I tried working on it in Rails and PHP in addition.

PHP

There is no better language in the world for putting together a quick, throwaway web mockup than PHP. Rails needs a database (unless you are ready to fight it). Most java frameworks need at least a build script. With PHP, you simply start with HTML, adding in chunks of code as you need them. You do not have to plan anything; you simply experiment and tweak it until you like what you see. It is seductive.

But when you move beyond the mockup phase, PHP loses some of its charm. You begin to struggle with inconsistent naming, a brittle directory structure, and the fact that you must do so much yourself.

Comparing PHP to 2 web frameworks is probably unfair. There are frameworks written in PHP, which might be more interesting, though I don't have any experience with them. And PHP does have a rich (although at times incongruous) set of libraries. Nonetheless, the structure and utilities that Rails offers become more appealing fairly early on in the process.

Ruby on Rails

My initial pass at MobileMusic was in PHP. I only produced the home page. The links went nowhere. There was no database involved. However, it did give me a much better feel for what I wanted.

It was time to move the application to Rails. The first step was to create the database, which was not difficult to do at this point. I threw together a sql script to set everything up. In Rails, I generated the models I needed. After this, it was time to work on the front end.

This was easy to carry over from my PHP mockup. I moved the header and left rail html portions to a layout. The main content of the page I put in a new view. The Rails version of this home page had only about 1/3 as many embedded lines of code, though the logic was essentially the same.

One hassle with Rails is that it is not always easy to load sample data. I'm not sure why. Rails has built-in tools to load YAML data files to populate the database for the the unit tests. No equivalent exists to load sample data for development. One logical solution would be to use a sql script, but connecting the record ids is tedious and error prone. Instead, I used a ruby ActiveRecord script. This seems a little better, but it is longer than the sql script would have been.

RhinoFaces (modified JSF)

I did not make it terribly far with this. I converted over some of the PHP version. I wanted to read from the database like I am doing in the Rails version. An obvious way to try this was to use my ActiveRecord knockoff from earlier this semester. Unfortunately, I ran into this error:

org.mozilla.javascript.EcmaError: ReferenceError: "importClass" is not defined.

It seems that the commands listed in http://www.mozilla.org/rhino/shell.html are not available the way that I am currently executing the JS scripts. There are methods to convert objects back and forth between Java and JavaScript, but it seems that I cannot just load scripts using the functions importClass(), load(), etc.

This complicates things a little. It seems like there will be a couple of ways around this. One possibility is to compile the scripts and treat them like java classes. Another might be to explore Mozilla's shell example program. However they are doing it should work in this case as well.

I have not experimented with either approach so far.


Week Nine

Updates for this week:

  • New class has been created to hold the JavaScript environment
  • JS environment now has a session scope (instead of application scope)
  • Views are now determined by the JS actions
  • ELResolver is now part of a composite resolver, so message bundles work

Navigation rules

The navigation rules are determined from the name of the action. Currently the XML navigation rules do not work, which is probably a fair trade for now. Along with replacing the managed bean with the JS controller, this has trimmed down the faces-config.xml file.

Here is the "before":

      <faces-config>
         <navigation-rule>
            <navigation-case>
               <from-outcome>success</from-outcome>
               <to-view-id>/success.jsp</to-view-id>
               <redirect/>
            </navigation-case>
            <navigation-case>
               <from-outcome>again</from-outcome>
               <to-view-id>/again.jsp</to-view-id>
            </navigation-case>
            <navigation-case>
               <from-outcome>failure</from-outcome>
               <to-view-id>/failure.jsp</to-view-id>
            </navigation-case>
            <navigation-case>
               <from-outcome>done</from-outcome>
               <to-view-id>/done.jsp</to-view-id>
            </navigation-case>
            <navigation-case>
               <from-outcome>startOver</from-outcome>
               <to-view-id>/index.jsp</to-view-id>
            </navigation-case>
         </navigation-rule>

         <managed-bean> 
            <managed-bean-name>quiz</managed-bean-name>
            <managed-bean-class>com.corejsf.QuizBean</managed-bean-class> 
            <managed-bean-scope>session</managed-bean-scope> 
         </managed-bean>
      </faces-config>
   

And the "after":

      <faces-config>
         <factory>
           <application-factory>edu.sjsu.rhinofaces.RhinoApplicationFactory</application-factory>
         </factory>
      </faces-config>
   

JS Function calls

This is still being done in the same kludgy way. I overrode getExpressionFactory() in my RhinoApplication class, but the method is never called. I'm not sure why.

The latest version of the javaquiz application is here.

JSF 2.0

TheServerSide.com had an article about JSF 2.0. The first paragraph:

The proposal focuses on ease of development (no config XML files), the use of templates, bookmarkable urls, and many more elements, including REST and AJAX usage in JSF. They're also focusing on ease of deployment, meaning that components should be "hot-deployable."

JRuby on Rails

One of the major goals for the JRuby developers has been to launch a JRuby version that will work with Ruby on Rails. They posted a recent announcement to http://jruby.codehaus.org. Version 0.9.8 was released on March 5th and passes 98% of the unit tests for Ruby on Rails.

Hot deployment

I tested out using the deployed directory to edit my application. This worked with the JSPs, but not with the JS controllers. I was able to change this. I do have some concerns, however.

The JS environments are stored in the session. This means that they are somewhat flexible anyway, but in something like the javaquiz application, restarting the session means that you go back to the beginning of the quiz. The trick is to reload the scripts, but maintain the state of the objects it contains.

Currently, I am doing this be recording each command executed. When I want to restore a session, I create a new JS context, reload the scripts, and then repeat all of the commands.

For the javaquiz example, this works great.

There might be a tiny bit off an issue if the repeated commands included database transactions. Credit card payments would be an even more interesting case.

A better approach would be to store the properties of all variables and restore them manually. I'm still searching for a good way to do this with Rhino's API. But for now, the current design illustrates the concept. Here is a new version of the javaquiz using this feature.


Week Eight

It is a short week, so I don't have a great deal to report. I took the java quiz sample application from Chapter 3 of "Core JavaServer Faces" and converted it to use my RhinoFaces setup. The result is here. The default ant task will build and deploy the application.

I uncovered a few issues and concerns in my implementation. First, I am not able to use the message bundle that was included in the original java quiz version. Second, the scope of the javascript interpreter is application wide, which means that two sessions share the same controller objects. Neither of these seem like they will be a hard problem to fix, but I have not gotten to them yet.

Another problem is the order that controller scripts are loaded. In the java quiz implementation, I have a problem.js script and a quiz.js script. Problem.js must be loaded first, or quiz.js won't understand 'new Problem()'. On my Mac, this worked great, since the scripts are loaded in the order that I want. On Linux, it blew up on me. I am not sure what the best way to get around it is. Does JS have the equivalent of an 'import' or 'require' utility? For the time being, I have just copied the problem.js portion to the quiz.js script.

One random thought... After thinking more about Charles Nutter's article from last week, it occurred to me that it might be worthwhile to set up things in such a way that a programmer could choose to use Groovy, BeanShell, or whatever language instead of JavaScript. This is probably a simple thing to set up in Java 6. When OS X catches up with the rest of the civilized world and gets Java 6, I'll pursue that a little more.

Phobos

I spent some time reviewing Phobos, and in particular reading through the Overview of Phobos document. In short, Phobos appears to be Rails written for Rhino. The only major missing piece is the ActiveRecord component.

The organization of Phobos is not exactly like that of Rails, but there are noticeable parallels. First of all, it has separate directories for the controllers, the views, and static files (plain html files, images, etc... The stuff that Rails throws into its public/ directory). Also, it has support for different environments built-in. Like Rails, these are 'development', 'testing', and 'production'. (How these are used was not entirely clear to me. For Rails, the different environments seem to mostly correspond to the DB setup. Perhaps this was a feature the Phobos team created without a complete picture of how it would be used.)

Phobos also copies the flash, which it directly attributes to Rails.

Phobos JS engines

Phobos has 2 different scripting engines. First, it can take .js files. These can even be used for views, which seems a little on the strange side. As a result, going to www.example.com/index.js might produce an html web page. This apparently does not cause any conflicts with the client side javascript, but it seems like it might confuse some users. Here is an example from the Phobos documentation of a "hello, world" script:

    response.setStatus(200);
    response.setContentType("text/html");
    writer = response.getWriter();
    writer.println("Hello from Javascript!");
    writer.flush();
  

The second engine is for embedded JavaScript files, with an extension of '.ejs'. (For Rails, the equivalent would be .erb). These look like standard jsp pages, except that they have javascript embedded instead of java code. One plus of the .jsp format over Rails's .erb format is the support for commenting out sections of a page. <%-- jsp comment --%> works far better than <%# rails comment %>. Because '%>' also closes code blocks in erb, it makes it difficult to comment out a large section of a page.

The overview specifically discusses the scripting engine in Java 6, and what features it lacked. They are:

  • Support for JS language extensions for XML
  • Bytecode compilation
  • Ability to subclass Java classes
  • "Extensible top-level functionality". Not really sure what that means...

For both engines, scripts are compiled on demand. If the source has changed since its last compilation, it will be recompiled on the fly.

Phobos Persistence?

The biggest noticeable difference between the structure of Phobos and Rails is that Rails includes built in support for persisting objects to the database. In Phobos, there is no equivalent to ActiveRecord. Also, though it has the same controllers/ and views/ directories, it has no models/ directory. (In Rails, this is where the scripts for all ActiveRecord subclasses are stored.)

The overview document does make passing reference to a 'networked database that ships as part of [GlassFish]'. Perhaps this is filling that role.


Week Seven

This week I completed most pieces needed for JavaScript to work as a controller. I am still having issues figuring out how to replace the NavigationHandler, but I don't think anything that I can't figure out.

Miscellaneous

Before I get started, I wanted to jot down a couple of random notes. First, I ran across this article from Charles Nutter about Grails. One interesting point is that most of Grails is actually written in Java. Groovy is a relatively thin cover over the architecture, he claims, and could be easily written in another language. (He is one of the core JRuby developers, so his bias is for that of course).

Also, for the glassfish installation instructions, I ran into one difference on my system. On page 5 of the instructions, it refers to 'glassfish\bin\adadmin'. On my setup, I have 'asadmin' instead. Otherwise, setup went without a hitch.

For the rest of this week's write-up, I'll cover the different pieces that were discussed, where they stand, and how I implemented them.

Fields and values

You need to find "user". There are two choices. a) Suck in all .js scripts in the controllers/ directory. One of them must define an object named user. b) Read in controllers/user.js and use its top level scope. I don't know which is better or more Rubyesque.

I went with option b. This seems less like Rails, but I'm no sure that is a bad thing. Rails divides its applications up into pieces by controllers, so that all pages under the /foo/ directory will be managed by foo_controller.rb (and application.rb). JSF's design does not seem to be as rigid in its setup, so being aware of all controllers would seem to be a positive.

Currently, the controllers/ directory lives under WEB-INF/classes/. This does not strike me as the best place for it, but it is the easiest for now.

You need to engineer a "value expression". Look at http://java.sun.com/javaee/5/docs/api/javax/el/ValueExpression.html. This is certainly doable. There must be some way for you to rig the ELContext, but for a first hack, you can just use a static reference to some object that knows all about the JS environment. JavaScript benefit: If "name" doesn't exist, it is automatically created. No more tedious bean coding!

Currently everything lives in the RhinoELResolver class. I ran into some problems last week. I think I am getting a better understading for how the JSF pieces work, so I can probably go back and redo this. I did not make it back to that this week.

You need to make and install a resolver. http://java.sun.com/javaee/5/docs/api/javax/el/ELResolver.html You know that you did everything right if you can make a simple script work that submits to itself and has <h:inputText value="#{user.name}"/> and <h:outputText value="#{user.name}"/>

This is done and working. I adapted the login example instead, which works.

Now on to actions. <h:commandButton value="#{user.verifyLogin}"/> This calls the method verifyLogin with no parameters, and it expects a string as return value. You'll have to proxy this into the JS code, which is easy. But I am fuzzy as to how exactly the MethodExpression (http://java.sun.com/javaee/5/docs/api/javax/el/MethodExpression.html) is produced. Either the ELResolver does it, or it stops one step short of parsing the entire #{...} expression, and http://java.sun.com/javaee/5/docs/api/javax/el/ExpressionFactory.html#createMethodExpression(javax.el.ELContext,%20java.lang.String,%20java.lang.Class,%20java.lang.Class[]) kicks in. If so, you need to know how to change the ExpressionFactory. You can find out which of the two it is by downloading the JSF RI (https://javaserverfaces.dev.java.net/download.html) and searching for MethodExpression.

It appears that the ExpressionFactory is in charge of this. However, I ran into some strange compile errors. This was the class:

public class RhinoExpressionFactory extends com.sun.el.ExpressionFactoryImpl {
    public RhinoExpressionFactory() {
        super();
    }
    public MethodExpression createMethodExpression(ELContext context, String expression,
            Class expectedReturnType, Class[] expectedParamTypes) {
        return super.createMethodExpression(context, expression,
                expectedReturnType, expectedParamTypes);
    }
}

The result was this error:

abstract method createMethodExpression(javax.el.ELContext,java.lang.String,java.lang.Class<?>,java.lang.Class<?>[]) in javax.el.ExpressionFactory cannot be accessed directly

ExpressionFactoryImpl is a concrete class, so this error does not seem to make much sense. I suspect generics is to blame. Instead, I replaced the ActionListener, caught the exception thrown, used that to determine the method that should be called, and then made a javascript call. This is almost certainly not the right way to do this. But for now, it works. In the example, 'tom' and 'secret' will take the user to the welcome page. Any other username/password combination will leave the user at the login page and display a message. All of this is controlled through the user.js controller.

A big part of the JS story needs to be ease of development during the coding phase. The programmer edits the JS file, and presto, something happens. But what? Can the same session continue to run? After all, when re-reading the JS file, the bean values will have changed, which would be confusing. Ideally, one might want the new methods and the old data. Can this be done with some fancy prototype chaining? Or should a new session be started? What happens in Ruby? What happens in GlassFish "hot deploy" mode?

If the programmer edits the already deployed jsp files, Glassfish will refresh them on the fly, keeping the old values. (This also seems to be the case with Rails). However, this does not work for my JS controllers currently.

Autodeploy for Glassfish will wipe out the session values.

I think one of Rails major pluses for ease of development is that it comes with everything you need to get started. In Java, you tend to need to assemble all of the pieces you are planning to use. While this is not so bad when you have everything installed already, it can be a major hurdle for setting up a new system, or breaking in new developers. If Charles Nutter is right, perhaps Grails already addresses much of this.

Once that works, you can replace the navigation handler. This has nothing to do with JS. I think the smart thing to do is to call the existing handler and if it fails, check if there is a view named outcomeString + ".jsp". That way, we don't take away the existing mechanism (which surely some people feel has tremendous value), but lazy programmers can just navigate by convention.

This is not done yet. For some reason, on startup I am getting:

java.lang.IllegalStateException: Application was not properly initialized at startup, could not find Factory: javax.faces.application.ApplicationFactory

In any case, I'm having trouble figuring out how I would tell if the NavigationHandler could not find the navigation rule. One thought I had was to check to see if the view had changed or not, and if it was expected to change. This seems kludgy though.

Here is the sample application. Although the navigation rules still need to be specified, it has no managed beans.


Week Six (a little late)

I am a few days late posting this, but so far I have been able to incorporate Rhino into JavaServer Faces. I took the login example from Chapter 1 of "Core JavaServer Faces", changed the application factory, and removed the managed UserBean object. The new login.war is available here. (Be forewarned that the code is an ugly, badly hacked-up job at the moment.)

Currently, the Rhino interpreter is embedded in RhinoELResolver. I am not using ValueExpressions at all. I had tried using them with VariableMapper, but calls to "VariableMapper vmap = context.getVariableMapper();" returned null. After banging my head against the wall for far too long, I decided to move on.

There are no separate Rhino scripts either. Currently, the RhinoELResolver creates a new object named user (within javascript) as soon as it initializes the interpreter. The end result is that properties for user only needed to be added to the jsp pages. (I added a 'favColor' property to demonstrate this). However, it won't currently work for anything but user.


Week Five

This week I began work on a small Rails application and reviewed one that I had worked on in the past.

ActiveRecord associations

Working on the sample application refreshed my memory on some of the features available in ActiveRecord. In addition to those that I already have in my JavaScript version, AR can specify associations within the models. They are:

  • has_one
  • has_many
  • belongs_to
  • has_and_belongs_to_many

These are fairly straightforward. Within the AR subclasses, each class specifies what other models it is related to. As long as certain database naming conventions are followed, nothing more needs to be done. From then on, calls to parent.save() and parent.delete() will do the same for the child instances as well.

An interesting feature is that each of these associations adds methods to the model. For instance, both the has_one and belongs_to methods add setter/getter methods to refer to the other object. An important point is that the parameter is the name of the other class, NOT an instance. ActiveRecord keeps track of all of its child classes, which is probably key to this. Is this something that JavaScript could do currently without any callbacks?

Rails Callbacks

Quick aside... Although I did not make much use of it in my demo this week, Rails provides a number of its own callbacks, such as 'before_filter', 'after_save', etc. This does not seem like anything that JavaScript could not already do, but it did get me to thinking about Domain Specific Languages. Perhaps one of the strengths of Ruby is that it makes it easy for the framework builders to make useful shortcuts for everyone else?


Week Four

This week I made an initial pass at a Rhino version of ActiveRecord and completed my survey of metaprogramming features in Ruby.

DynaRecord

For the time being, I have named my ActiveRecord clone 'DynaRecord'. It reads from the Database to get the fields, determines the table name from the name of the constructor function, and adds all fields found as properties of the object. It has save(), findFirst(), and removeFromDatabase() functions that will automatically manage the interaction with the database provided that certain conventions are followed. (Beyond the naming, each table must have its own ID field, which must be named ID.)

For this example, I wrote this sql script. It will create an 'Employees' table and add a single record to it. The full DynaRecord script, including the Employee example, is available here.

To create a new Employee class that would read from the employees table, this is the code needed:

   function Employee(props) {
      this.superclass = DynaRecord;
      this.superclass(arguments.callee, props);
   }
   Employee.prototype = new DynaRecord();
   Employee.prototype.constructor = Employee;

This is only a few lines long, and no database information needs to be repeated here. However, it is still a little cumbersome. The ideal might look something like:

   function Employee(props) {
      this.superclass = DynaRecord;
   }

But in any case, once the constructor function has been done, creating and managing new Employee objects is fairly straightforward:

   // This will create a new employee object.
   var maturin = new Employee({firstname: 'Stephen', lastname: 'Maturin', title: 'Naval Surgeon'});
   maturin.save();

   // Once it has been saved, it is easy to look up from the database.
   maturin = Employee.findFirst({lastname: 'Maturin'});
   
   // Properties can be changed, so we can assign a new title to our employee.
   maturin.title = 'Master Spy';
   maturin.save();

   // Espionage is a dangerous business...  We may need to delete this record later
   maturin.removeFromDatabase();

Note that this just uses the standard version of Rhino. No more advanced metaprogramming features were used. However, to get a lighter syntax, it would be handy to intercept properties as they are set. In fact, this and a utility similar to methodMissing() would appear to bring JavaScript up to the same level of metaprogramming as Ruby.

Ruby/JavaScript Metaprogramming

My other major task was to put up a page listing the metaprogramming features of Ruby, how they are used in Rails, and what equivalents JavaScript has. That is available here.

In short, JavaScript seems to match most of Ruby's metaprogramming features, and often more cleanly. The major shortcoming it has is in hooks and callbacks. By intercepting the setting of properties, JavaScript can cover almost all of these cases.


Week Three

This week I fell a little behind due to some emergencies that came up. I dug into the Rhino code more to figure out where I could insert a '__propertyMissing()' call. I have managed to identify one possible point, though it is not functional yet.

Some thoughts on dynamic typing

Last week, one point discussed was dynamic typing, and whether that could be an advantage in creating a framework like Rails. I would argue that it is, though perhaps not a tremendous one.

One fundamental principle in Rails is DRY (Don't Repeat Yourself). ActiveRecord is a good example of this. Outside of the database, you do not need to specify the available fields anyplace. Therefore, when you update the database, the fields magically appear.

This would still be possible in an explicitly typed language like Java, but the problem becomes much more challenging. Following the Rails mentality, we could set default types. Fields that have '_date' somewhere in the name could be stored by default as a Date object. '_count' fields could be stored as ints. (We'll ignore the complications with the primitive/Object split for now). But what about a price field? Would it be an int, a double, or a BigDecimal? Depending on the application, any of these might be appropriate.

Because of Java's explicit typing, this would almost always require more wiring in of type information somewhere in the code or configuration files. This is a direct violation of the DRY principle. For smaller applications, this almost certainly translates to a productivity hit. For larger applications, there probably comes a point when the advantages of explicit typing begin to make up for this.

Singleton classes

This was an area where I was still a little fuzzy last week, but I found a copy of David Black's "Ruby For Rails". Chapter 13 has a detailed discussion on the metaprogramming features of Ruby, with a strong bent for how they are used in Rails.

In short, every object has 2 classes. The first is the named class, which is shared among all objects of that class. The second is the singleton class, which belongs only to that specific instance. This allows a programmer to add methods just for that instance of the object.

This seems like a neat feature, but I'm not sure what the advantage of it is. It is used frequently in Rails, though it is not clear to me why that was needed over a given method call.

Inherited method

I had not spotted this in my explorations last week, but David Black's book put special emphasis on this method. 'Class' has an 'inherited()' method that is called whenever a class is subclassed. ActiveRecord uses this to track all of its subclasses. By doing this, it can dynamically change the settings for all ActiveRecord objects, if desired.


Week Two

This week I am cataloging the features of metaprogramming used in Ruby on Rails.

method_missing

'method_missing' is the Ruby function that is called for an object when a method call cannot be found. This feature is often used in Rails for cosmetic purposes. For instance, it is used by ActiveRecord to allow calls like 'Student.find_by_student_id(12345)'. This would search the students table for all entries where student_id was equal to 12345.

Behind the scenes, Rails catches this call by overriding method_missing. It then converts this to
'Student.find(:first, :conditions => ["student_id = ?", 12345])'.

Also, this is used to allow direct reference to the fields. At the time the record is created, these fields are read from the table definition and stored in an '@attributes' hash. When the name of a field is called as a method on this class, method_missing will retrieve the field with the same name as the method called. (For example, 'student.student_id').

It is tempting to write this feature off as merely syntactic sugar, but it seems more powerful than that. This allows Ruby programmers to create limitless methods, and can give the code a much greater degree of clarity.

Here is an example creating Lisp-like list functions in Ruby arrays:

# Modifications to give the Array class the car/cdr abilities of Lisp.
class Array
  # Returns the head element
  def car
    first
  end

  # Returns the tail
  def cdr
    slice(1,length)
  end

  # This will give more advanced list functions, like cadar or caar.
  # However, unlike in Lisp, there will be no limit
  # to the available methods.  'caadaaddadaadaaddadr' could be called
  # if the programmer so decided (and had a really sick sense of humor).
  def method_missing(method_called, *args, &block)
    meth_name = method_called.to_s
    if meth_name =~ /^c(a|d)+r$/
      list = self
      meth_name.reverse.scan(/./).each do |op|
        if op == 'a'
          list = list.car
        elsif op == 'd'
          list = list.cdr
        end
      end
      return list
    else
      super(method_called, *args, &block)
    end
  end
end

list = [[0, [1, 2], 3], 4]

puts list.caadar  #prints 1

Note: I had a computer mishap and lost my original writeup of the rest of this section late on Wednesday night. This section will be a somewhat abbreviated version for now.

Mixins

Ruby allows users to create 'modules'. Classes are one, but not the only, example. One common use of a non-class module is to collect related methods (similar to classes of static methods in Java, like java.lang.Math).

Another, more interesting type of module is called a "mixin". Mixins add in functionality to other classes, like "Comparable" or "Enumerable". These serve in much the same role as interfaces do in Java, with the obvious benefit that they add actual functionality, instead of just obligations. (They do add in obligations as well -- the added methods typically make use of other methods that must be defined in the class).

I'm not sure if this really qualifies as a metaprogramming technique, but it does allow programmers to add in their own desired functionality to any existing class (as I did with the Array class in the previous example, albeit without a module). This would seem to solve many of the same problems where metaprogramming techniques might be used.

Aliasing a Method

This is heavily used in ActiveRecord, and seems to be one of the core pieces of the design in Rails. The 2 methods used primarily in this are 'alias_method' and (to a lesser extent) 'define_method'. These appear to be used in tandem to create a wrapper around methods. The method is aliased to a new name, and the original method name is overridden by the wrapper method (typically defined with 'define_method').

Singleton Classes?

I'm still a little fuzzy on this... Singleton classes seem to be an important aspect of metaprogramming in Ruby, and they are used in ActiveRecord. These seem to take the place of metaclasses in other languages like Smalltalk. Dave Thomas discusses these briefly on page 382 of his "Programming Ruby" book (second edition). Ola Bini also discusses these in some greater depth, but I'm still not sure I am getting it. It seems that each of these singleton classes are basically mixins associated with just a single object.


Week One

This week, I modified rhino to have a 'functionMissing' feature similar to Ruby's 'methodMissing'. In the sample script, the function 'addTwo' does not exist, but calling it will still work since the functionMissing() function does that.

Here is the build.xml file. The default target will download the modified js.jar file and test.js script. Once the files have been downloaded, then 'ant run' will rerun the script without re-downloading everything.


Some notes for the week...

Thoughts on Reflex

Reflex is Eric Tanter & co.'s "Open Reflective Extension" framework for Java. What is particularly interesting about it is that Reflex has introduced another level into the development process. The architect of the metalevel is supposed to determine what MOP features are available for a given set of applications.

The challenge with MOPs is to find the right balance between efficiency and power. While method intercession and similar features can be very useful, there is a definite cost in terms of performance. When the feature is not needed, it is better to leave it out so that the application does not have to pay this overhead.

The problem is the that balance point between these concerns varies by application. By introducing the architect role, Tanter hopes to give developers the flexibility that they need to provide exactly the right features.

But is this really a unique design? It seems that Smalltalk and Lisp could do the same fairly easily. Is the novelty here that Reflex is a flexible MOP for Java? In fact, Tanter compares Reflex primarily to other MOPs for Java. This suggests that Reflex's success is not in really providing a new feature, but in providing it to a more rigid language like Java.

Nonetheless, Reflex provides a clear picture of what hooks might be made available, and just as importantly, when they can be introduced.

(Not sure I am interpreting this part correctly...) Introducing hooks at compile time allows the performance cost of introducing these hooks to be paid up front. However, this might not provide the flexibility needed. (Also, for scripting languages, this might not be an option). For this reason, Reflex allows hooks to be introduced at load time or object creation time instead.

One of the major strengths of Reflex seems to be that an object is no more reflective than it needs to be. Even 2 instances of the same class can have different reflective feautres. The framework allows objects to have hooks added or removed to them easily, so that the performance overhead does not have to be paid if it is not needed. Also, great pains pains have been taken to allow non-reflective and reflective objects interact smoothly.