Navigation

RSS 2.0 New Entries Syndication Feed Atom 0.3 New Entries Syndication Feed

Show blog menu v

 

General

Use it

Documentation

Support

Sibling projects

RIFE powered

Valid XHTML 1.0 Transitional

Valid CSS!

Blogs : Archives

< Java standards complient HTML component hoax   Bytecode generation rocks >
RIFE v0.7.1 has been released

Below are the highlights of this release.

  • purging authentication is now the default approach [ more ]
  • major and incompatible changes to 'call' continuations [ more ]
  • support for URL localization [ more ]
  • template type-specific default resource bundles [ more ]
  • alternate localization method [ more ]
  • deferred validation initialization [ more ]
  • support for more constraints [ more ]
  • embedded element definitions can now provide values [ more ]
  • reworked database transactions [ more ]
  • alternate site structure and element declaration methods [ more ]
  • major speed optimizations [ more ]

Purging authentication is now the default approach

The shipped authentication elements used a naming scheme that made the automated purging of outdated authentication sessions available through a specialized name. We noticed that people therefore never really looked further and used unpurged authentication schemes without realizing that purging has to be setup independently in that case. The element declarations have thus been renamed like this:

rife/authenticated/database.xml

becomes=>

rife/authenticated/databaseunpurged.xml

rife/authenticated/memory.xml

becomes=>

rife/authenticated/memoryunpurged.xml

rife/authenticated/mixed.xml

becomes=>

rife/authenticated/mixedunpurged.xml

rife/authenticated/databasepurging.xml

becomes=>

rife/authenticated/database.xml

rife/authenticated/memorypurging.xml

becomes=>

rife/authenticated/memory.xml

rife/authenticated/mixedpurging.xml

becomes=>

rife/authenticated/mixed.xml

People that have been consciously using unpurged authentication have to change the names of the element declarations; and those that did it without knowing should do nothing. They will be using purging back-ends from now on without having to change anything.

[ top ]

Major and incompatible changes to 'call' continuations

Continuations that used the call(String exitname) method invocation to execute another element could optionally use the answer(Object value) method invocation to return a value to the caller. Control was automatically returned to the caller when the called element finished processing (a bit like a default return statement at the end of a method).

Initially this seemed like a good idea, but in practise it means that existing elements all have to be rewritten to explicitly keep a continuation going by using pause and call all over the place. This was necessary to prevent that the execution of any element in the flow finishes the processElement method and thus resumes the initial continuation.

The automatic answer at the end of processElement has now been removed and to resume a prior continuation, one has to always use an answer call. This thus means that all 'call' continuations that relied on the automatic answer, should insert answer() calls at the end of their processElement method.

For clarity, the simplest possible call continuation looks like this now:

public class Caller extends Element
{
    public void processElement()
    {
        call("exit_to_callee");
    }
}
public class Callee extends Element
{
    public void processElement()
    {
        answer();
    }
}

[ top ]

Support for URL localization

Localizing content with RIFE is already very versatile, but it's not sufficient to create fully translated versions of applications. URLs are an important part of your web application and make it possible for people to remember and access distinct locations directly. The site structure has thus been extended to allow the usage of different URLs according to the default localization language.

The default localization language is 'en' if it hasn't been defined by the user. You can modify it by providing a value for the L10N_DEFAULT_LANGUAGE configuration parameter.

Instead of regular URLs, you can now use the following definition in your site structure, for example:

<element id="ROOT" file="root.xml" url="fr:/racine,nl:/wortel,/root"/>

This will result in the following behaviour:

  • if the default language is 'fr',
    the URL '/racine' will be used;
  • if it's 'nl',
    the URL '/wortel' will be used;
  • and for any other language,
    the URL '/root' will be used.

[ top ]

Template type-specific default resource bundles

When localizing an application, it's common practice to use a few resourcebundles that are shared by the whole application. Since it's tedious to have to explicitely add them to all the templates that are instantiated, and since sometimes templates are automatically instantiated by reusable elements, it's handy to be able to setup a collection of default resource bundles.

You set this up in your configuration file and it's specific for each template factory type. The latter is important since it makes no sense to add content resource bundles to all SQL templates or Java templates.

For example:

<list name="TEMPLATE_DEFAULT_RESOURCEBUNDLES_ENGINEHTML">
    <item>l10n/graphics</item>
    <item>l10n/text</item>
</list>

will result in executing the following Java code after the instantiation of each enginehtml (the standard type) template:

template.addResourceBundle(Localization.getResourceBundle("l10n/graphics"));
template.addResourceBundle(Localization.getResourceBundle("l10n/text"));

[ top ]

Alternate localization method

While resource bundles offer a good method to isolate localized text snippets, it's sometimes interesting to be able to conditionally display parts of templates with lots of markup. For this purpose, resource bundles are actually awkward to use. Templates are therefore now able to set blocks automatically to values, according to the default localization language (L10N_DEFAULT_LANGUAGE configuration parameter). This can be done with the <!--B 'LANG:id:language'--> block syntax.

For example:

<!--V 'LANG:value1'-->default<!--/V--> [!V 'LANG:value2'/]
<!--B 'LANG:value1:nl'-->ja ja<!--/B-->
[!B 'LANG:value2:fr']oui oui[!/B]
[!B 'LANG:value2:en ']yes yes[!/B]

will display this when the default language is 'en'

default yes yes

or this when the default language is 'fr'

default oui oui

or this when the default language is 'nl'

ja ja [!V 'LANG:value2'/]

[ top ]

Deferred validation initialization

Before, it was recommended to initialize the static bean validation rules and constraints in the default constructor of the bean so that they were always available when needed. With large collections of beans with a complex validation rules setup, this however creates quite a performance and memory overhead. Therefore, you can now optionally move all your validation initialization logic to the dedicated activateValidation() method. This method will only be called the first time any validation-related method is called on a particular bean instance and thus not at every instantiation of the bean.

It's thus recommended to transform this:

public class Credentials extends Validation
{
    private String mLogin = null;
    private String mPassword = null;
    private String mLanguage = null;
    
    public Credentials()
    {
        addConstraint(new ConstrainedProperty("login").maxLength(6).notNull(true));
        addConstraint(new ConstrainedProperty("password").maxLength(8).notNull(true));
        addConstraint(new ConstrainedProperty("language").notNull(true));
    }

    /* ... accessors ... */
}

into this:

public class Credentials extends Validation
{
    private String mLogin = null;
    private String mPassword = null;
    private String mLanguage = null;
    
    public Credentials()
    {
    }

    protected void activateValidation()
    {
        addConstraint(new ConstrainedProperty("login").maxLength(6).notNull(true));
        addConstraint(new ConstrainedProperty("password").maxLength(8).notNull(true));
        addConstraint(new ConstrainedProperty("language").notNull(true));
    }

    /* ... accessors ... */
}

[ top ]

Support for more constraints

Two new constraints have been added to the constraints facility:

displayedRaw

This indicates that the value of the property should be displayed as-is when it's being output. No encoding or transformation will be performed.

A typical use of this is when you allow administrators to write HTML snippets, you don't want the actual HTML tags to be encoded and the source code to be displayed. Instead, you want to output the submitted data exactly as it was entered so that all HTML formatting does its usual work.

By default, this is set to false.

editable

This indicates that the value of the property can't be changed or edited by a user.

A typical use of this is when you have a bean with a number of properties that should be filled in directly through a form, but with some other properties that are not allowed to be modified by the user (id, modification date, ...). If you use submission beans or input beans, you only want the application to accept values for the properties that can be edited and not for the others. Like this, you're sure that no malicious or accidental outside data modification can occur.

By default, this is set to true.

[ top ]

Embedded element definitions can now provide values

When embedding elements in templates, you can now access the default value from within the embedded elements. This is handy when you have modular embedded elements that have to be setup for different uses when they are inserted in the templates.

For example, consider this template snippet:

The element "<!--V 'ELEMENT:.SIMPLE'-->this is the value<!--/V-->" is being embedded.

Inside the SIMPLE element's implementation, you can now use the getEmbedValue() method, which will in this case return:

this is the value

[ top ]

Reworked database transactions

The DbQueryManager now has a new inTransaction(DbTransactionUser) method. It ensures that all the instructions in the provided DbTransactionUser instance are executed inside a transaction and committed afterwards. This doesn't mean that a new transaction will always be created. If a transaction is already active, it will simply be re-used. The commit will also only take place if a new transaction has actually been started by the active inTransaction invocation, otherwise it's the responsibility of the enclosing code to execute the commit. If a runtime exception occurs during the execution and a new transaction has been started beforehand, it will be automatically rolled back.

If you need to explicitly roll back an active transaction, use the rollback method of the DbTransactionUser class. If you use a regular rollback method, it's possible that you're inside a nested transaction and that after the rollback other logic continues to be executed outside the transaction. Using the correct rollback method, stops the execution of the active DbTransactionUser and breaks out of any number of them nesting.

Since you sometimes use a transaction without being interested in returning a result, you can use the DbTransactionUserWithoutResult class which doesn't require you to write a meaningless 'return null;' statement at the end of the implemented method.

It's recommended to always use transactions through the inTransaction method since it ensures that transactional code can be re-used and enclosed in other transactional code. Correctly using the regular transaction-related methods requires great care and planning and often results in error-prone and not reusable code.

For example:

final Insert insert = new Insert(mDatasource).into("valuelist").field("value", 232);
final DbQueryManager manager = new DbQueryManager(datasource);
manager.inTransaction(new DbTransactionUserWithoutResult() {
        public void useTransactionWithoutResult()
        throws InnerClassException
        {
            manager.executeUpdate(insert);
            manager.executeUpdate(insert);
        }
    });
 

You can throw regular exceptions inside the transaction with the DbTransactionUser's throwException(Throwable) method. The transaction will be rolled back if the active inTransaction method started a new transaction. An instance of InnerClassException will be thrown and can be caught outside the inTransaction method. The original exception you wanted to throw is then available through the InnerClassException's getCause() method.

[ top ]

Alternate site structure and element declaration methods

Element declarations and site structures have up to now always been defined in one fixed XML format. A first step has been made to enable the transparent integration of other declaration methods. Each declaration method is identified through a unique identifier which allows you to mix them freely. This identifier can be added in front of the declaration name of the element or site (the file attribute in the XML format). If no identifier is added, it defaults to the 'corexml' declaration method which is what you've always been using. RIFE currently ships with one others declaration method: 'manual'. This essentially means that the rest of the declaration is up to you and that the declaration name will not be automatically processed (with corexml, the declaration name is parsed as an XML document that builds the structure). We'll provide some documentation later about how to define your own identifiers and we're in the process of implementing other structure builders for various purposes.

Here is a small example of how to declare an entire site structure with all the elements in Java only. You'll see this is the same as what's done by the 4 XML files in the basic numberguess example.

/*
 * file: src/tutorial/numberguess/Site.java
 */
package tutorial.numberguess;

import com.uwyn.rife.engine.SiteBuilder;
import com.uwyn.rife.rep.BlockingParticipant;

public class Site extends BlockingParticipant
{
    private Object    mSite = null;

    protected void initialize()
    {
        SiteBuilder    builder = new SiteBuilder("manual:numberguess", getResourceFinder());
        builder
            .setArrival("START")
            
            .enterElement("manual:START")
                .setImplementation("tutorial.numberguess.Start")
                .setUrl("/start")
            
                .addInput("gameid")
                .addExit("started")
                .addOutput("gameid")
            
                .addFlowLink("started", "GUESS")
                .addDataLink("gameid", "GUESS", "gameid")
            .leaveElement()
            
            .enterElement("manual:GUESS")
                .setImplementation("tutorial.numberguess.Guess")
                .setUrl("/guess")
            
                .addInput("gameid")
                .enterSubmission("perform_guess")
                    .addParameter("guess")
                .leaveSubmission()
                .addExit("start")
                .addExit("success")
                .addOutput("gameid")

                .addFlowLink("start", "START")
                .addDataLink("gameid", "START", "gameid")

                .addFlowLink("success", "SUCCESS")
                .addDataLink("gameid", "SUCCESS", "gameid")
            .leaveElement()
            
            .enterElement("manual:SUCCESS")
                .setImplementation("tutorial.numberguess.Success")
            
                .addInput("gameid")
                .addExit("start")

                .addFlowLink("start", "GUESS")
            .leaveElement();
        
        mSite = builder.getSite();
    }
    
    protected Object _getObject(Object key)
    {
        return mSite;
    }
}
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
  - file: classes/rep/participants.xml
  -->

<!DOCTYPE rep SYSTEM "/dtd/rep.dtd">

<rep>
    <participant name="ParticipantSite">tutorial.numberguess.Site</participant>
</rep>

[ top ]

Major speed optimizations

Several areas of the framework have been profiled and reworked to get much better speed. Most notably, many standard collections that store primitives have been replaced by their primitive counterparts of PCJ (Primitive Collections for Java) and the StringUtils.encode* methods have been rewritten to get a 5x better encoding speed (which should affect almost all web applications).

[ top ]

posted by Geert Bevin in RIFE on Apr 21, 2004 11:40 AM : 0 comments [permalink]
 

Comments

Add a new comment

Comments on this blog entry have been closed.

< Java standards complient HTML component hoax   Bytecode generation rocks >
 
 
 
Google
rifers.org web