Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migration of unmigrated content due to installation of a new plugin

unmigrated-inline-wiki-markup

...

{scrollbar}

Service Configurations

This is an area of Tapestry IoC that is often least well understood. Tapestry services often must have some configuration to fine tune exactly what they do. One of the interactions between modules is that these service configurations are shared: they may be contributed into by any module.

Let's start with the most basic kind, the unordered configuration.

Unordered Service Configurations

One of Tapestry's features is the ability to package assets (images, style sheets, JavaScript libraries, etc.) inside JAR files and expose those to the client. For example, an application URL

...

/assets/org/example/mylib/mylib.js

...

would

...

refer

...

to

...

a

...

file,

...

myllib.js,

...

stored

...

on

...

the

...

classpath

...

in

...

the

...

/org/example/mylib

...

folder.

That's fine for most cases, but for certain file extensions, we don't want to allow a client browser to "troll" for the files, as the contents could compromise security. For example, downloading a .class file is bad: a clever client might download one that contains a hard-coded user name or password.

Thus, for certain file extensions, Tapestry guards the resource by attaching an MD5 digest for the resource to the URL. The checksum is derived from the file contents; thus it can't be spoofed from the client unless the client already has the file contents.

This is controlled by the ResourceDigestGenerator service, which uses its configuration to determine which file extensions require an MD5 digest.

Contributing to a Service

Main Article: Tapestry IoC Configuration

The Tapestry module makes a contribution into the service configuration:

Code Block
borderStylesolid


That's fine for most cases, but for certain file extensions, we don't want to allow a client browser to "troll" for the files, as the contents could compromise security. For example, downloading a .class file is bad: a clever client might download one that contains a hardcoded user name or password.

Thus, for certain file extensions, Tapestry guards the resource by attaching an MD5 digest for the resource to the URL. The checksum is derived from the file contents; thus it can't be spoofed from the client unless the client already has the file contents.

This is controlled by the [ResourceDigestGenerator|../../apidocs/org/apache/tapestry5/services/ResourceDigestGenerator.html] service, which uses its configuration to determine which file extensions require an MD5 digest.

h2. Contributing to a Service

The Tapestry module makes a contribution into the service configuration:

{code|borderStyle=solid}
  public static void contributeResourceDigestGenerator(Configuration&lt;String&gt;Configuration<String> configuration)
  {
    configuration.add(&quot;class&quot;"class");
    configuration.add(&quot;tml&quot;"tml");
  }{code}

This

...

is

...

a

...

service

...

contribution

...

method

...

,

...

a

...

method

...

that

...

is

...

invoked

...

to

...

provide

...

values

...

for

...

a

...

configuration.

...

We

...

'll

...

see

...

how

...

the

...

service

...

receives

...

these

...

contributions

...

shortly.

...

The

...

Configuration

...

object

...

is

...

how

...

values

...

are

...

added

...

to

...

the

...

service

...

's

...

configuration.

...

Other

...

parameters

...

to

...

a

...

service

...

configuration

...

method

...

are

...

injected

...

much

...

as

...

with

...

a

...

service

...

's

...

constructor,

...

or

...

a

...

service

...

builder

...

method.

...

How

...

does

...

Tapestry

...

know

...

which

...

service

...

configuration

...

to

...

update?

...

It

...

's

...

from

...

the

...

name

...

of

...

the

...

method,

...

anything

...

after

...

the "contribute" prefix is the id of the service to contribute to (the match against service id is case insensitive).

Here, the configuration receives two values: "class" (a compiled Java class) and "tml" (a Tapestry component template).

Say your application stored a file on the classpath needed by your application; for illustrative purposes, perhaps it is a PGP private key. You don't want any client to able to download a .pgp file, no matter how unlikely that would be. Thus:

Code Block
borderStylesolid
 &quot;contribute&quot; prefix is the id of the service to contribute to (the match against service id is case insensitive).

Here, the configuration receives two values: &quot;class&quot; (a compiled Java class) and &quot;tml&quot; (a Tapestry component template).

Say your application stored a file on the classpath needed by your application; for illustrative purposes, perhaps it is a PGP private key. You don&apos;t want any client to able to download a .pgp file, no matter how unlikely that would be. Thus:

{code|borderStyle=solid}
public class MyAppModule
{
 public static void contributeResourceDigestGenerator(Configuration&lt;String&gt;Configuration<String> configuration)
 {
   configuration.add(&quot;pgp&quot;"pgp");
 }
}{code}

The

...

contribution

...

in

...

MyAppModule

...

doesn

...

't

...

replace

...

the

...

normal

...

contribution,

...

it

...

is

...

combined

...

.

...

The

...

end

...

result

...

is

...

that

...

.class,

...

.tml

...

and

...

.pgp

...

files

...

would

...

all

...

be

...

protected.

...

Receiving

...

the

...

Configuration

...

A

...

service

...

receives

...

the

...

configuration

...

as

...

an

...

injected

...

parameter

...

...

...

not

...

of

...

type

...

Configuration

...

(that

...

's

...

used

...

for

...

making

...

contributions),

...

but

...

instead

...

is

...

of

...

type

...

Collection:

{|=
Code Block
borderStyle
solid
}
public class ResourceDigestGeneratorImpl implements ResourceDigestGenerator
{
  private final Set&lt;String&gt;Set<String> digestExtensions;

  public ResourceDigestGeneratorImpl(Collection&lt;String&gt;Collection<String> configuration)
  {
      digestExtensions = new HashSet&lt;String&gt;HashSet<String>(configuration);
  }

  . . .
}{code}

In

...

many

...

cases,

...

the

...

configuration

...

is

...

simply

...

stored

...

into

...

an

...

instance

...

variable;

...

in

...

this

...

example,

...

the

...

value

...

is

...

transformed

...

from

...

a

...

Collection

...

to

...

a

...

Set.

...

These

...

kinds

...

of

...

unordered

...

configurations

...

are

...

surprisingly

...

rare

...

in

...

Tapestry

...

(the

...

only

...

other

...

notable

...

one

...

is

...

for

...

the

...

TypeCoercer

...

service).

...

However,

...

as

...

you

...

can

...

see,

...

setting

...

up

...

such

...

a

...

configuration

...

is

...

quite

...

easy.

...

Ordered

...

Configurations

...

Ordered

...

configurations

...

are

...

very

...

similar

...

to

...

unordered

...

configurations

...

...

...

the

...

difference

...

is

...

that

...

the

...

configuration

...

is

...

provided

...

to

...

the

...

service

...

as

...

a

...

parameter

...

of

...

type

...

List.

...

This

...

is

...

used

...

when

...

the

...

order

...

of

...

operations

...

counts.

...

Often

...

these

...

configurations

...

are

...

related

...

to

...

a

...

design

...

pattern

...

such

...

as

...

Chain

...

of

...

Command

...

or

...

Pipeline

...

.

Here,

...

the

...

example

...

is

...

the

...

Dispatcher

...

interface;

...

a

...

Dispatcher

...

inside

...

Tapestry

...

is

...

roughly

...

equivalent

...

to

...

a

...

servlet,

...

though

...

a

...

touch

...

more

...

active.

...

It

...

is

...

passed

...

a

...

Request

...

and

...

decides

...

if

...

the

...

URL

...

for

...

the

...

Request

...

is

...

something

...

it

...

can

...

handle;

...

if

...

so

...

it

...

will

...

process

...

the

...

request,

...

send

...

a

...

response,

...

and

...

return

...

true.

...

Alternately,

...

if

...

the

...

Request

...

can

...

't

...

be

...

handled,

...

the

...

Dispatcher

...

returns

...

false.

{|=
Code Block
borderStyle
solid
}
public void contributeMasterDispatcher(OrderedConfiguration&lt;Dispatcher&gt;OrderedConfiguration<Dispatcher> configuration, . . .)
{
  // Looks for the root path and renders the start page

  configuration.add(&quot;RootPath&quot;"RootPath", new RootPathDispatcher(. . .), &quot;"before:Asset&quot;");

  // This goes first because an asset to be streamed may have an file extension, such as
  // &quot;".html&quot;", that will confuse the later dispatchers.

  configuration.add(
          &quot;Asset&quot;"Asset",
          new AssetDispatcher(. . .),
          &quot;"before:PageRender&quot;");

  configuration.add(&quot;PageRender&quot;"PageRender", new PageRenderDispatcher(. . .));

  configuration.add(&quot;ComponentAction&quot;"ComponentAction", new ComponentActionDispatcher(. . .), &quot;"after:PageRender&quot;");
}{code}

With

...

an

...

OrderedConfiguration

...

,

...

each

...

contribution

...

gets

...

a

...

name,

...

which

...

must

...

be

...

unique.

...

Here

...

the

...

names

...

are

...

RootPath,

...

Asset,

...

PageRender

...

and

...

ComponentAction.

...

The

...

add()

...

method

...

takes

...

a

...

name,

...

the

...

contributed

...

object

...

for

...

that

...

name,

...

and

...

then

...

zero

...

or

...

more

...

optional

...

constraints.

...

The

...

constraints

...

control

...

the

...

ordering.

...

The

...

"after:

...

" constraint

...

ensures

...

that

...

the

...

contribution

...

is

...

ordered

...

after

...

the

...

other

...

named

...

contribution,

...

the

...

"before:

...

" contribution

...

is

...

the

...

opposite.

...

The

...

ordering

...

occurs

...

on

...

the

...

complete

...

set

...

of

...

contributions,

...

from

...

all

...

modules.

...

Here,

...

we

...

need

...

a

...

specific

...

order,

...

used

...

to

...

make

...

sure

...

that

...

the

...

Dispatchers

...

don

...

't

...

get

...

confused

...

about

...

which

...

URLs

...

are

...

appropriate

...

...

...

for

...

example,

...

an

...

asset

...

URL

...

might

...

be

...

/assets/tapestry5/tapestry.js.

...

This

...

looks

...

just

...

like

...

a

...

component

...

action

...

URL

...

(for

...

page

...

"assets/tapestry5/tapestry

...

" and

...

component

...

"js").

...

Given

...

that

...

software

...

is

...

totally

...

lacking

...

in

...

basic

...

common-sense,

...

we

...

instead

...

use

...

careful

...

ordering

...

of

...

the

...

Dispatchers to

...

ensure

...

that

...

AssetDispatcher

...

is

...

checked

...

before

...

the

...

ComponentAction

...

dispatcher.

...

Receiving

...

the

...

Configuration

...

The

...

configuration,

...

once

...

assembled

...

and

...

ordered,

...

is

...

provided

...

as

...

a

...

List.

...

The

...

MasterDispatcher

...

service

...

configuration

...

defines

...

a

...

Chain

...

of

...

Command

...

and

...

we

...

can

...

provide

...

the

...

implementation

...

using

...

virtually

...

no

...

code:

{|=
Code Block
borderStyle
solid
}
  public static Dispatcher buildMasterDispatcher(List&lt;Dispatcher&gt;List<Dispatcher> configuration, ChainBuilder chainBuilder)
  {
    return chainBuilder.build(Dispatcher.class, configuration);
  }{code}

[ChainBuilder|../../

ChainBuilder is a service that builds other services. Here it creates an object of type Dispatcher in terms of the list of Dispatchers. This is one of the most common uses of service builder methods ... for when the service implementation doesn't exist, but can be constructed at runtime.

Mapped Configurations

The last type of service configuration is the mapped service configuration. Here we relate a key, often a string, to some value. The contributions are ultimately combined to form a Map.

Tapestry IoC's symbol mechanism allows configuration values to be defined and perhaps overridden, then provided to services via injection, using the @Value annotation.

The first step is to contribute values.

Code Block
borderStylesolid
apidocs/org/apache/tapestry5/ioc/services/ChainBuilder.html] is a service that _builds other services_. Here it creates an object of type Dispatcher in terms of the list of Dispatchers. This is one of the most common uses of service builder methods ... for when the service implementation doesn&apos;t exist, but can be constructed at runtime.

h1. Mapped Configurations

The last type of service configuration is the mapped service configuration. Here we relate a key, often a string, to some value. The contributions are ultimately combined to form a Map.

Tapestry IoC&apos;s [symbols|../symbols.html] mechanism allows configuration values to be defined and perhaps overridden, then provided to services via injection, using the [Value|../../apidocs/org/apache/tapestry5/ioc/annotations/Value.html] annotation.

The first step is to contribute values.

{code|borderStyle=solid}
  public static void contributeFactoryDefaults(MappedConfiguration&lt;StringMappedConfiguration<String, String&gt;String> configuration)
  {
    configuration.add(SymbolConstants.FILE_CHECK_INTERVAL, &quot;1000&quot;"1000"); // 1 second
    configuration.add(SymbolConstants.FILE_CHECK_UPDATE_TIMEOUT, &quot;50&quot;"50"); // 50 milliseconds
    configuration.add(SymbolConstants.SUPPORTED_LOCALES, &quot;en&quot;"en");
    configuration.add(&quot;"tapestry.default-cookie-max-age&quot;", &quot;604800&quot;"604800"); // One week
    configuration.add(&quot;"tapestry.start-page-name&quot;", &quot;start&quot;"start");
    configuration.add(&quot;"tapestry.scriptaculous&quot;", &quot;"classpath:${tapestry.scriptaculous.path}&quot;");
    configuration.add(
            &quot;"tapestry.scriptaculous.path&quot;",
            &quot;"org/apache/tapestry5/scriptaculous_1_7_1_beta_3&quot;");
    configuration.add(&quot;"tapestry.jscalendar.path&quot;", &quot;"org/apache/tapestry5/jscalendar-1.0&quot;");
    configuration.add(&quot;"tapestry.jscalendar&quot;", &quot;"classpath:${tapestry.jscalendar.path}&quot;");
  }{code}

These

...

contribution

...

set

...

up

...

a

...

number

...

of

...

defaults

...

used

...

to

...

configure

...

various

...

Tapestry

...

services.

...

As

...

you

...

can

...

see,

...

you

...

can

...

even

...

define

...

symbol

...

values

...

in

...

terms

...

of

...

other

...

symbol

...

values.

...

Mapped

...

configurations

...

don

...

't

...

have

...

to

...

be

...

keyed

...

on

...

Strings

...

(enums

...

or

...

Class

...

are

...

other

...

common

...

key

...

types).

...

When

...

a

...

mapped

...

configuration

...

is

...

keyed

...

on

...

String,

...

then

...

a

...

case-insensitive

...

map

...

is

...

used.

...

Wiki Markup
{scrollbar}