Skip to content

TeaServlet Applications

nicholashagen edited this page Jan 23, 2012 · 3 revisions

Previous - Plugins | Table of Contents | Next - Lifecycle

Applications in Tea are essential to the Tea templates. They provide the context methods that are accessible within Tea templates. Applications implement the org.teatrove.teaservlet.Application interface. Applications provide an init(ApplicationConfig) method to provide the application configuration and initialize the application. The configuration is available through the init section of the application. The ApplicationConfig also provides access to the servlet context of the TeaServlet. More importantly, the ApplicationConfig provides the ability to lookup plugins. This allows an application to utilize plugins to provide further data. For example, an application may be bound to the general DataSourcePlugin, but the actual implementation (JDBC, Hibernate, etc) is controlled by the plugin configuration completely independent of the application. If we consider the UserDatabase plugin example in the Plugin section, we could use that plugin accordingly:

<teaservlet>
    <applications>
        <UserApplication>
            <class>com.example.UserApplication</class>
            <init>
                <dataSourceName>UserDatabase</dataSourceName>
            </init>
        </UserApplication>
    </applications>
</teaservlet>
public class UserApplication implements Application {
    ...
    public void init(ApplicationConfig config) {
        String dataSourceName = config.getProperties().getString("dataSourceName");
        this.dataSource = (DataSource) config.getPlugin(dataSourceName);
    }

    public User getUser(Integer userId) {
        return (User) this.dataSource.getObject(userId);
    }
}

Applications are just the configuration points. Applications provide a context that provides the actual methods for Tea templates. The getContextType method should return the type of context that the application will use. Generally, this is an appropriate interface of the implementation class. The getContext method returns the actual implementation instance of the context. The resulting context instance is provided to the TeaServlet and invoked whenever a Tea template invokes a method on the context. All public methods of the context type are accessible by Tea templates.

Contexts in Tea generally take on two forms: stateless and stateful. Stateless contexts do not maintain internal state and are thread safe. Stateful contexts have internal state or are bound to each request and/or response. Stateless contexts are generally only created once and returned on subsequent invocations (ie: singleton). Stateless contexts are also the most performant. Stateful contexts, on the other hand, have to be created with each request/response.

Stateless applications almost never have application-specific configuration. To avoid creating an application per stateless context, TeaServlet provides the org.teatrove.teaapps.apps.DefaultApplication that instantiates the context once and returns the same instance per request. The associated context is configured via the DefaultApplication init block. The contextClass property specifies the fully-qualified name of the context class to instantiate. The class must have a public default constructor. If the context class implements org.teatrove.teaapps.Context interface, then the configuation properties of the applications will be accessible through the init(ContextConfig) method.

<teaservlet>
    <applications>
        <GreetingApplication>
            <class>org.teatrove.teaapps.apps.DefaultApplication</class>
            <init>
                <contextClass>com.example.GreetingContext</contextClass>
                <greeting>Hello</greeting>
            </init>
        </GreetingApplication>
    </applications>
</teaservlet>

Deciding between a stateless and a stateful context all depends on the use case. If the context methods require access to the request or response details, then a custom application is most likely needed to create the context per request. Generally, stateless contexts should be used unless specific reasons not to.

Deciding between using the DefaultApplication or custom application depends on what type of initialization needs to occur. If the context is stateless, has a default constructor, and has no configuration or only simple configuration, then the DefaultApplication will suffice. Otherwise, a custom application may need to exist to properly configure and return the context.

Substitution Blocks

Methods within contexts generally have two forms. The first is a standard method such as toLowerCase(String), getSomeData(), etc. These methods may also support variable arguments within JDK 1.5 (ie: avg(int... numbers)). The second method contains an additional parameter org.teatrove.tea.runtime.Substitution. Substitution blocks (Tea User Manual) are used to pass Tea code to a method. You can think of substitution blocks as a tag library in JSTL with a body. The method may use the substitution parameter to invoke the body zero or more times. Consider the following Tea template

<% template test(Integer count)

count = count ?: 10
invoke(count) {
    'Hello World'
}
public class InvokeContext {
    public void invoke(int count, Substitution substitution) {
        for (int i = 0; i < count; i++) {
            substitution.substitute();
        }
    }
}

This will invoke and print 'Hello World' the given count number of times. Substitutions are great for loops/repetition and logic. Consider a cache(int ttl, Substitution s) method. This will either invoke the substitution and cache it or it will not invoke it returning the previously cached data. See the Substitution JavaDocs for more information.

Administration Applications

As part of the TeaServlet Administration console, TeaServlet provides another form of an application as org.teatrove.teaservlet.AdminApp. Administration applications provide one or more Tea templates as administration links that are added to the Administration console via the getAdminLinks method. The getAdminLinks method takes a org.teatrove.teaservlet.AppAdminLinks that may have one more links added containing the link title and the link template. The link template is the fully-qualified dotted-notation of the template.

The administration application must also provide a context as with all applications. The context generally contains the administration functions used by the admin templates.

The templates and the TeaServlet configuration for an administration application are generally bundled together as a library. The templates are also generally precompiled so that an end user only needs to include the library dependency without further configuration. See Tea Compiler for Maven for more information on precompiling Tea templates and see Tea Configuration for automatic discovery of Tea configuration files within libraries.

The TeaAdmin project itself is a great example of an administration application.

Application Metadata Information

The TeaServlet Administration console contains the ability to display all applications and their resulting methods they may invoke. This provides an alternative to standard JavaDocs that allow template developers to easily see from the administration console what methods are available. However, by default, only the general signature is provided (ie: String doSomething(int, String, int)). This, by itself, has limited meaning as it does not describe what the actual arguments are or what the method does.

Tea contains a special Maven plugin that generates metadata classes for applications and contexts known as BeanInfo. TeaServlet knows how to discover these classes and retrieve the metadata to display on the administration console. If using Maven, it is suggested to configure this plugin in order to generate the necessary metadata. The following is a basic example of including the plugin:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-javadoc-plugin</artifactId>
    <version>2.7</version>
    <executions>
        <execution>
            <id>generate-beaninfo</id>
            <phase>generate-sources</phase>
            <configuration>
                <useStandardDocletOptions>false</useStandardDocletOptions>
                <reportOutputDirectory>${project.build.directory}/generated-sources/beaninfo</reportOutputDirectory>
                <destDir>.</destDir>
                <doclet>org.teatrove.toolbox.beandoc.BeanDocDoclet</doclet>
                <docletArtifact>
                    <groupId>org.teatrove</groupId>
                    <artifactId>toolbox</artifactId>
                    <version>${toolbox.version}</version>
                </docletArtifact>
            </configuration>
            <goals>
                <goal>javadoc</goal>
            </goals>
        </execution>
    </executions>
</plugin>

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>build-helper-maven-plugin</artifactId>
    <version>1.5</version>
    <executions>
        <execution>
            <id>add-beaninfo-sources</id>
            <goals>
                <goal>add-source</goal>
            </goals>
            <configuration>
                 <sources>
                     <source>${project.build.directory}/generated-sources/beaninfo</source>
                 </sources>
             </configuration>
         </execution>
     </executions>
 </plugin>

The plugin basically works by utilizing the JavaDoc process to inspect all sources. For each class and method, it adds metadata for the javadocs, the parameter names, and the parameter docs. This makes viewing the functions on the administration console much richer and more explanatory.

Previous - Plugins | Table of Contents | Next - Lifecycle