[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: accumulator generator (Java)



   Date: Fri, 24 May 2002 15:50:35 -0400
   From: "Anton van Straaten" <anton@appsolutions.com>

   Something else.  When I first came across anonymous inner classes in Java, I
   experimented with them for a variety of things, such as for example wrapping
   database transactions:

	   new my.Transaction() {
		   protected Object body() throws Exception {
			   // logic for specific transaction goes here
		   }
	   }.run();

   ...which allows centralizing of common behavior like for example transaction
   begin/commit/rollback, exception handling, and logging, which otherwise must
   be repeated and scattered throughout a program.  However, access to the
   enclosing closure is so restrictive that it's difficult to write this kind
   of code in real life without continually bumping into the restrictions.  I
   came across the Jikes anomaly when code that I had written, which worked
   fine, wouldn't build under the Sun compiler.

The product that I've been contributing to for the last couple of
years is written in Java and based on an XML DBMS.  We do exactly what
you're talking about.  It's true that you have to add some "final"
declarations, and sometimes it would have been nice if you could have
modified variables in the containing block, but even in light of this
problems, we'd never consider doing without this!  It's extremely
important to centralize that behavior, which has many subtle
aspects that needed very careful design and debugging.

Here's an example:

  /**
   * Enqueue this message event to the node that has the PFE that handles the
   * PRN of this process, filling in the PRN if this is a new process.  If the
   * PFE that handles this PRN is on this node, it will just do the work
   * directly (as an optimization).  However, if it is also from the PFE on
   * this node, it will still enqueue it, so that the sending process will be
   * continued before the called process executes.
   **/
  private void sendEventToPFE(final MessageEvent event) {
    String processName = event.to().processToStart();
    final int prn;
    if (processName != null) {
      prn = resources_.getPRN(processName);
      event.to().correlation().getPid().setPRN(prn);
    } else {
      prn = event.to().correlation().getPid().getPRN();
    }
    new LexTxn() { public Object action() {
      PFE pfe = PFEFactory.instance();
      if (pfe.handlesPRN(prn) && !event.from().isPFE()) {
        boolean newPid = false;
        if (event.pid().getTick() == 0) {
          // Just use the queue manager to fill in the Pid, then send to PFE.
          QueueManagerFactory.instance().generatePid(event.pid());
          newPid = true;
        }
        pfe.handleEvent(event);
        if (newPid) {
          // handleEvent filled in the collaboration use.  So that this
          // case returns the same kinds of collaborations as the case
          // where the message is enqueued, we null it out before returning.
          event.to().correlation().setCollaborationUse(null);
        }
      } else {
        QueueManagerFactory.instance().enqueue(new QueueMessage(event));
      }
      return null;
    }}.execute(log_);
  }

"event" and "prn" had to be declared "final", and the "return null" is
because we don't happen to need to return anything to the caller in
this case.  Annoyances, yes, but in practice pretty tolerable.