The concept is fairly simple if you are familiar with JSF, so I'm not taking any credit for this pattern.

For your whole view layer, create beans that act like commands or units of work. They have property methods that provide state and methods that provide action behavior (not arguments and return a String).

public HelloWorldController
{
   protected int count = 0;
   public void setName(String name);
   public String getName();
   public String incrementCount() {
      this.count++;
   }
   public String getMessage() {
      return "Hello "+this.name
         +", I've been called "
         +this.count+" times.";
   }
}

In the above example, any framework we choose Struts, JSF, Webwork, String, etc can update the properties on that bean and also call and use the "action method" called 'incrementCount'.

At this point you are probably thinking this is pretty trivial. But lets get to the core of 'Pull Controller' concept. Since all of our controllers are POJO beans, the view data is all provided via bean properties. JSTL and other tags can easily 'pull' this data out of the controller bean at render time. To me, this is more efficient than managing session/request state, then having stateless actions acting upon data and pushing it around into views that may not even need the processed junk.

Another bonus of going with a bean controller model is leveraging PropertyChangeListeners. For certain edit operations, we cache data in the user's session WITHIN a POJO bean controller. An example would be caching the Customers for a specific account a user is working with. But since this is the web, a user could probably find a way to change the account they are working with. Instead of constantly checking for the account being changed, just use PropertyChangeListeners.

AppController appCtlr = new AppController();
appCtlr.setServiceLocator(serviceLocator);
appCtlr.setAccount(accountA);

CustomerController custCtlr = new CustomerController();
custCtlr.setAppController(appCtlr) {
  this.appCtlr = appCtlr;
  this.appCtlr.addListener("account", this);
}

// create and cache internally
List customers = custCtlr.getAccountCustomers();

// return cached version
customers = custCtrl.getAccountCustomers();

// change account, will notify custCtlr
appCtlr.setAccount(accountB);

// fresh data for accountB
customers = custCtrl.getAccountCustomers();

I hope that example wasn't too complex ;-) It did also highlight the fact that now your controller isn't framework dependent and situations could be scripted in junit.

Some developers may also bring up issues with lazy loading data in the JSP ala JSTL. There are two work arounds for this. Either provide an "action method" that does this:

public String listAccountCustomers() {
   try {
      this.getAccountCustomers();
      return "pass";
   } catch (Exception e) {
      // log
      return "fail";
   }
}

Or- use the JSTL catch tags which everyone seems to forget.

Anyways, going back to the pull model. Using a pull model at the view layer can also allow for more efficient caching of content where the objects aren't important, just the rendered view. Your controller could tie in a view cache manager with PropertyChangeListeners to instead cache rendered views-- store the rendered Employee data, not the Employee bean and regenerate the view everytime.

For use in existing web frameworks, JSF is a no brainer for this bean controller idea. For Struts, it wouldn't be very hard to create Bean actions, check out IBatis's JPetstore. Again, Spring lends itself to support Struts also in wiring your controller together.

In summary, the Bean Controller is an easy way to provide generic controller behavior that is adaptable to any web framework. In addition, it's becomes easy to unit test controller behavior and reuse components without scripting everything under the sky into actions or procedures (this is Object Oriented programming right?).