Aranea-MVC 1.1.5

June 27th, 2008 by Martti Tamm

All known important bugs are fixed in Aranea 1.1.5 and we encourage you to upgrade. In addition, our ivy repository and dependence management has been improved for you to use. Try it out!

Enjoy the summer! ;)

Aranea-MVC 1.1.4

June 16th, 2008 by Martti Tamm

Aranea 1.1.4 is now available! It includes some small-scale new features and some fixes to improve the quality.

Note that it is planned as the last feature release for 1.1 branch. If there are some bugs reported then a bugfix-only release of Aranea 1.1 shall follow, otherwise not. New features will be planned to 1.2.

Notable new possibilities include IN-style filtering (a field value must be one of user-selected values) in lists, and inserting event links to messages.Next, we are working on the next 1.2 release that should provide a solution for the browser back-button. We also plan to provide some milestones so you can try, whether you might have problems with it.

Read the rest of this entry »

Aranea-MVC 1.1.3

May 21st, 2008 by Martti Tamm

After a month of development, the new release is ready. Most of the effort was devoted to improvement, and here is a quick overview of major changes:

  • lists have built-in support for PostgreSQL - PostgreListSqlHelper;

  • lists have built-in support to filter rows requiring the value to start or end with the user-provided value;

  • new tags for a list row check box (<ui:listRowCheckBox/>, <ui:listSelectAllCheckBox/>) and a list row radio button (<ui:listRowRadioButton/>);

  • a bug was fixed that caused Aranea MVC to not work with the Safari browser.

Read the rest of this entry »

Aranea-MVC 1.1.2

April 16th, 2008 by Martti Tamm

First of all, starting from this new release I, Martti Tamm, will be taking over the development process at Aranea. Taimo still provides some support for specific cases during this spring, but mostly he is in exile :P . Shortly about me, I’ve been using Aranea for about two years now, and I try to bring some new energy to the project. In addition, to make you feel comfortable, I have a certificate to prove that at least I know how to write code in Java 1.4…

This release of Aranea MVC 1.1.2 contains some bugfixes related to visual behaviour of modal popup, calendar box, and optimized ajax performance. As it contains only fixes without major code changes, it’s worth to upgrade!

As usual, if you are having any problems or ideas, please report them or share them in the forum so we can improve Aranea to be stable and easier to use.

Aranea-MVC 1.1.1

March 19th, 2008 by Taimo Peelo

For the wonderers—yes 1.1 final had rather a silent release in February and now is the time for nicely symmetrical minor version update that fixes a little bug and updates documentation that concerns Aranea javascript.

We’d also like to thank all people who have reported issues and keep our forums lively. We couldn’t have done it so far without you :)

First milestone of 1.2 branch which implements state versioning (and thus back-button support) is due within few days.

Letting end-user confirm destructive actions

February 21st, 2008 by Taimo Peelo

Aranea 1.1 standard component chain enriches Environment with a context called ConfirmationContext. This can be used for executing some code conditionally, depending on user actions. Context interface is simple and consists of following methods:

JAVA:
  1. public interface ConfirmationContext {
  2.   void confirm(Closure onConfirmClosure, String message);
  3.   String getConfirmationMessage();
  4. }

When confirmation is registered (with confirm() method), rendering mechanism will present end-user with the browser standard message box and ask for confirmation of requested action. Depending on users choice, action encapsulated in onConfirmClosure either will get executed or not.

Combined with TransitionHandler, confirmation could be asked whenever the user performs navigation that would make active flow unreachable and flow contains data that has not yet been saved.

JAVA:
  1. getFlowCtx().setTransitionHandler(
  2.   new CancelConfirmingTransitionHandler(
  3.      new ShouldConfirmOnUnsavedData(),
  4.      "Some data not saved yet. Continue anyway?"
  5.   )
  6. );

Here CancelConfirmingTransitionHandler registers the confirmation whenever FlowContext.cancel() is called from active flow and Predicate ShouldConfirmOnUnsavedData evaluates to true. Only after user confirms the navigation event will flow transition actually be performed.

ConfirmationContext and TransitionHandlers together are a reliable and convenient way of preventing end-users shooting themselves in the foot :).

Aranea-MVC 1.1-RC1

February 7th, 2008 by Taimo Peelo

And ... the 1.1-RC1 is here sooner than expected :) Mainly this is due to pushing back-button support into the 1.2 release cycle. It will still be done very soon (within this February). This release contains fixes for bugs which were reported since last milestone and documentation updates.

Enjoy!

Aranea-MVC 1.1-M6

January 31st, 2008 by Taimo Peelo

Latest release is now very near to release candidate stage. Only major thing that we still want to add into the 1.1 branch is mechanism for supporting browser back button :)

See the change log & download the release. And let us know of anything that needs to be improved ;)

Number guess game with continuations

November 17th, 2007 by rein

We found a nice illustration of using continuations among RIFE examples and wrote the Number guess game also using Aranea Continuations (for the introduction read Aranea and Swing get Continuations).

The following game chooses a random integer between 0 and 100 and lets the user to guess it. Each time a hint is given whether the right answer is higher or lower than the entered:


CODE:
  1. class NumberGuessingGameExample extends JPanel {
  2.  
  3.     private static final int MIN = 0;
  4.     private static final int MAX = 100;
  5.  
  6.     @Resumable
  7.     void init() {
  8.         setLayout(new BorderLayout());
  9.  
  10.         JLabel label = new JLabel("Guess a number from " + MIN + " to " + MAX);
  11.         JTextField field = new JTextField();
  12.         field.setHorizontalAlignment(JTextField.CENTER);
  13.         JButton button = new JButton("Guess");
  14.  
  15.         add(label, BorderLayout.NORTH);
  16.         add(field, BorderLayout.CENTER);
  17.         add(button, BorderLayout.SOUTH);
  18.         updateUI();
  19.  
  20.         int answer = MIN + (int) (Math.random() * (MAX - MIN + 1));
  21.         int guesses = 0;
  22.         int guess = -1;
  23.  
  24.         while (guess != answer) {
  25.             SwingBlockingUtil.waitForOneAction(button);
  26.  
  27.             try {
  28.                 guess = Integer.parseInt(field.getText());
  29.             } catch (NumberFormatException e) {
  30.                 continue;   // ignore
  31.             }
  32.  
  33.             if (guess &lt;MIN || guess&gt; MAX) {
  34.                 continue;   // ignore
  35.             }
  36.  
  37.             field.setText("");
  38.  
  39.             if (answer &lt;guess) label.setText("The answer is lower than " + guess);
  40.             if (answer&gt; guess) label.setText("The answer is higher than " + guess);
  41.  
  42.             guesses++;
  43.         }
  44.  
  45.         System.out.println("You found the answer " + answer + " by " + guesses + " guesses");
  46.     }
  47.  
  48.     public static void main(String[] args) {
  49.         NumberGuessingGameExample panel = new NumberGuessingGameExample();
  50.         JFrame frame = new JFrame();
  51.         frame.add(panel);
  52.         panel.init();
  53.     }
  54.  
  55. }

Notice that the program consists of one main loop which takes a user input, processes it and gives a response. This is like reading standard input. To do the same in Swing, usually one is forced to register an ActionListener and the program flow jumps to that - different method when an action occurs.

Here waitForOneAction() blocks the program flow until the button receives an action (like java.io.Reader.read()).

Under the hood still an ActionListener is used. When waitForOneAction() is invoked a snapshot is taken from the program exceution and when ActionListener.actionPerformed() is reached this snapshot is used to resume the program.

The whole source code can be accessed at:
http://svn.araneaframework.org/repos/aranea-continuations/

How Aranea Integration works: part I

October 24th, 2007 by Taimo Peelo

This is the first in the series of tutorial articles laying out the foundations of Aranea Integration in practical way. It introduces the base classes of Aranea Integration which form the core of server-side integration—handle sessions, requests and responses in a way that allows hosted components to function (keep this diagram open while reading!).

Base interface for Aranea components that host components/actions from whatever framework is called HostComponent.

CODE:
  1. /**
  2. * Represents the Aranea {@link Component} that
  3. * hosts some foreign framework component.
  4. */
  5. public interface HostComponent extends Component {
  6.   /**
  7.   * This method must return the session attribute
  8.   * <em>Map</em> specific to hosted component.
  9.   * @return map that will be used for storing the
  10.   *               session accessible to hosted foreign
  11.   *               component
  12.   */
  13.   public Map getHostedSessionAttributes();
  14. }

and has just one method -- for retrieval of session attributes managed by the hosted component. The request and response are tuned to hosted components needs too, but since request and response in HTTP protocol are stateless, these need not be part of HostComponent interface but can be managed separately and statelessly. HostComponent base implementation is extremely simple:

CODE:
  1. /**
  2. * Base class for Aranea widgets that host foreign
  3. * components. Provides session storage for hosted
  4. * foreign components.
  5. */
  6. public class BaseHostWidget
  7. extends BaseApplicationWidget implements HostComponent {
  8.   private final Map sessionAttributeMap = new HashMap();
  9.  
  10.   public Map getHostedSessionAttributes() {
  11.     return sessionAttributeMap;
  12.   }
  13. }

As one can see it completely lacks methods for actual management of session attributes.The class that manages session access is called SessionWrapper:

CODE:
  1. /* One and only constructor **/
  2. public SessionWrapper(
  3.     HttpSession session,
  4.     HostComponent sessionHolder)

SessionWrapper ensures that the session modifications by hosted component will affect only the concrete hosted component. It is created anew at each request by IntegrationRequestWrapper (note that only way to access session in a web application is through current request).

Other base wrappers that make hosted component feel at home are already mentioned IntegrationRequestWrapper and IntegrationResponseWrapper. IntegrationRequestWrapper is created by some concrete HostComponent implementation, passing in the original request and itself.

CODE:
  1. new IntegrationRequestWrapper(
  2.     HttpServletRequest original, HostComponent host);

The IntegrationResponseWrapper takes care that everything that is done to it only affects the wrapped instance -- so that original request is left unchanged and can be passed to any number of other Aranea components or hosted components (in which case it is obviously wrapped in its own IntegrationRequestWrapper). Often some parts of original request are preprocessed in some way in IntegrationRequestWrapper extensions -- i.e. the fully hierarchial component based request parameters that Aranea uses are converted into flat namespace for action-based frameworks, i.e.

CODE:
  1. public class BaseActionBasedRequestWrapper
  2. (final HttpServletRequest request,
  3. final HostComponent host) {
  4.   super(request, host);
  5.   preprocessRequestParameters();
  6. }

where preprocessRequestParameters() takes all the 'scoped' data meant for hosted component and converts this into flat namespace parameters that action based frameworks expect. This allows to reuse actions many times on one page, as each action can receive separate data.

Foreign response itself is held in IntegrationResponseWrapper which allows HostComponent to post-process response when needed. Postprocessing is most often done to scope the request parameters expected by hosted component in a way that they will be unique. How exactly this is done is highly dependent on hosted framework. For action-based frameworks this might mean post-processing HTML forms, for component based frameworks the postprocessing might even be unnecessary when the hosted components' 'root' component is given the right scope to begin with (i.e. with JSF NamingContainer).

Other crucial part of the IntegrationResponseWrapper is the overriden encodeURL(url) method. By servlet specification, all URLs that are to generate requests to (hosted) web application must go through this method before written out to response. IntegrationResponseWrapper overrides this method so that later incoming request can be identified as request to component hosted by Aranea. Identification is done by AraneaIntegrationFilter which is quite ordinary servlet filter, except it prevents the request from directly reaching the hosted framework and directs it to Aranea component hierarchy where it will be processed by all interested components including the HostComponent implementation which originally generated the request.

This briefly covers all current integration base classes. For more detailed information, one can take a look at org.araneaframework.integration.common package in the Aranea Integration project.