Pustefix Reference Documentation

Version 0.12.x

This documentation relates to the latest Pustefix release from the 0.12 branch.


Table of Contents

1. Configuration Files
1.1. Java property files in Pustefix
1.2. ContextXMLServlet configuration format
1.3. DirectOutputServlet
1.4. Configuration fragments file format
1.5. FactoryInitServlet (factory.xml)
1.6. Global properties (pustefix.xml)
2. Advanced topics
2.1. Role-based authorization
Example
2.2. Object-to-XML mapping
Serialization process
Custom serializers
2.3. Annotation-based IWrapper creation
IWrapper annotations
3. Modules
3.1. FireDebug
Usage

List of Tables

1.1. Exception processor properties

Chapter 1. Configuration Files

1.1. Java property files in Pustefix

Some parts of the Pustefix frameworks are configured using Java properties. To ease this configuration Pustefix provides you with a special XML format which is read instead of the usual Java property file format. This format provides some customization mechanism to allow configuration options to depend on settings like the makemode or the machine the application is being built on.

The structure of a standard .xml property file is very easy:

<standardprops version="1.0"
  xmlns="http://pustefix.sourceforge.net/2004/properties"
  xmlns:cus="http://www.schlund.de/pustefix/customize"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://pustefix.sourceforge.net/2004/properties http://pustefix.sourceforge.net/2004/properties.xsd">
      

The cus namespace is needed to use the customization tags explained below.

  <properties>
    <prop name="statuscodefactory.messagefile">common/dyntxt/statusmessages.xml</prop>

      

The prop tag is the most primitive way to enter a single property. The example above would simply result in the java property statuscodefactory.messagefile=common/dyntxt/statusmessages.xml.

  </properties>
</standardprops>
      

Pustefix allows to customize the creation of the property files in certain ways. When the file is being read, the system uses settings defined in common/conf/buildtime.prop (which itself is automatically generated by the build system) to provide the parameters used in the customization tags:

  • makemode The value of the ant property makemode, which can be passed on the ant commandline but will more commonly be specified in the environment variable MAKE_MODE. This can be used to easily switch preferences depending on the "mode" that is active when the application is built, e.g. "test" on development machines, and "prod" on the production servers. The value is supplied as the parameter mode. Note that the value of MAKE_MODE also determines if certain features are allowed like the possiblity to use the Pustefix editor or to get the XML result instead of the rendered page. These features are turned off for security reasons when the mode is "prod".

  • The user id (uid) of the user that starts the build process.

  • The full qualified domainname (as the parameter fqdn) of the machine you start the build process.

  • The name of the machine (machine) you start the build process on.

  • Any ant property (__antprop_*) defined within the build file.

Certain customization tags work with these parameters:

<properties
  xmlns:cus="http://www.schlund.de/pustefix/customize">
  <prop name="foo">
    <cus:uid/>
  </prop>
      

Use cus:uid to reference the user that started the build process. In the same way you can use cus:machine and cus:fqdn to insert the value of the supplied XSLT parameter

  <choose>
    <when test="$mode='test'">
      
    </when>
    <when test="$uid='pfixuser'">
      
    </when>
    <when test="$machine='server1'">
      

These choose and when elements are allowed only within properties elements. The three test nodes above test for one of the supplied XSLT parameters...

    </when>
    <when test="$mode='prod' and $uid='pfixuser'">
      
    </when>
    <when test="$mode='prod' or machine='server1'">
      

...you can use boolean operators to combine tests

    </when>
    <otherwise>
      

The "default test" that will always pass.

    </otherwise>
  </choose>
</properties>
      

If you think the customization system really looks like XSLT, you are almost right as in fact the test expressions are coded using XPath - the same standard XSLT is using, too.

This customization mechanism is not only available within the XML property files but also in most other Pustefix configuration files.

1.2. ContextXMLServlet configuration format

Most projects use one or a (small) number of de.schlund.pfixxml.ContextXMLServlet servlets that drive the business logic of the application. All pages that are to be generated via XSLT from a data XML tree are handled by a servlet of this type.

This servlet uses a configuration file that has a special syntax. However properties and customization in this file work nearly the same way as explained for the standard property definitions.

<contextxmlserver version="1.0"
  xmlns="http://pustefix.sourceforge.net/2004/properties"
  xmlns:cus="http://www.schlund.de/pustefix/customize"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://pustefix.sourceforge.net/2004/properties http://pustefix.sourceforge.net/2004/properties.xsd">
  <servletinfo depend="MyProject/conf/depend.xml" name="AUniqueNameForTheServlet">
      

The attributes depend and name are mandatory. If depend starts with a '/' the value is used unchanged, otherwise (which is the usual case) it's interpreted as a path relative to the docroot.

    <editmode allow="true|false"/>
      

allow needs to be set to true if you want to be able to use the pustefix editor. You can wrap this tag within a customization element to allow edit mode only in certain modes (e.g. test mode). The whole node is optional.

    <ssl force="true|false" modes="ListOfModes"/>
      

force must be set to true if the servlet needs to run under SSL. You can wrap this tag within a customization element to force use of SSL only in certain modes (e.g. prod mode). The whole node is optional.

    <defaultstate class="a.state.Class"/>
    <defaultihandlerstate class="another.state.Class"/>
      

defaultstate and defaultihandlerstate are both optional. The class attribute must be given. a.state.Class should de a descendant of de.schlund.pfixcore.workflow.app.StaticState and another.state.Class should be a descendant of de.schlund.pfixcore.workflow.app.DefaultIWrapperState (unless you really know what you are doing). They are used to set the defaults for the state tag used when processing the pagerequest tag (see there for more info).

  </servletinfo>
  
  <context defaultflow="AFlowName" authpage="APageName" synchronized="true">
      

Attribute Description
defaultflow Mandatory. Must reference a valid pageflow (See below).
authpage Optional. It must be given, if the servlet should supply a login/authentification page. If given, it must reference a valid pagerequest with an auth child node.
synchronized Optional. Defaults to true. If set to true, only one request per session is handled concurrently. If set to false all requests will be handled concurrently, requiring thread-safe business logic.

    <resource class="AContextResource">
      

class is mandatory, must be a ContextResource. There may be multiple resource tags given.

      <implements class="An_Interface">
      

class is mandatory, must be an interface implemented by the ContextResource. There may be more than one implements tag for a ContextResource, but each interface must be unique in the whole context. In other words: it's possible for a ContextResource to implement more than one interface, but not possible for one interface to be implemented by two ContextResources used in the same Context definition.

      </implements>
      <properties>
      

The whole node is optional.

        <prop name="AName">AValue</prop>
      

prop is mandatory and can be used multiple times. It's similar to the use as a child of pagerequest/properties, but used here to create properties that are related to a context resource implementation. The resulting property looks like this: context.resourceparameter.AContextResource.AName=AValue Customization tags may be used around a property to make it depend on a certain makemode, etc.

      </properties>
    </resource>
  </context>
  
  <scriptedflow name="AName" file="path/to/scriptfile.xml"/>
      

There may be an arbitrary number of scriptedflow tags, but each one must have a unique name. Scripted flows are a special method to control a session and do automatic requests based on initial user input.

  <role name="MY_ROLE">
    <pageaccess names="mypage*"/>
  </role>
      

You can define an arbitrary number of roles and assigned authorizations here, for details see Role-based authorization.

  <pageflow name="AName" final="APageName" stopnext="true|false">
       

There may be multiple pageflow tags defined, but you need at least one (which must be referenced by the defaultflow attribute above). We only describe the normal case without using variants. See here for more information on how to handle variants of pageflows.

Attribute Description
name Mandatory. Must be a unique name.
final Optional, must reference a page with a valid pagerequest definition given in this property file. There may be many pageflows defined for a servlet. A page may well be used in more than one pageflow.
stopnext Optional, defaults to false. If given and true, the pageflow will stop at the next accessible page after the current page even if this page would normally be skipped in the workflow because it doesn't need any input.

    <flowstep name="AnotherPageName" stophere="true|false">
      

Attribute Description
name Mandatory. Must reference a valid pagerequest. Usually there are many flowsteps defined in a pageflow.
stophere Optional, if true the pageflow will stop at this step unconditionally if the submit originated from a step that's before this one in the pageflow. See also the stopnext attribute of the tag which is quivalent to specifying stophere="true" for every single flowstep.

      <oncontinue applyall="true|false">
      

This tag (which is optional) starts a sequence of test/action pairs. The tests are XPath expressions which work on the DOM tree as produced by the flowstep's associated state (note that the navigation is not inserted into the DOM tree at this stage, and the /formresult/formvalues and /formresult/formerrors paths are also not present). The pageflow system calls the tests whenever a state returns a ResultDocument (before it continues with other stuff e.g. a pageflow run). The applyall attribute is optional. If given and true, all actions with matching conditions are executed, if not given or false (the default) only the first action with a matching condition is executed.

        <when test="A_XPath_Expression">
      

The when tag contains the XPath expression to try in it's test attribute. If this attribute is omitted, the whole condition is considered to be true.

          <action type="jumpto" page="APage" pageflow="APageFlow">
      

The action tag denotes the FlowStepAction to execute. The type attribute is mandatory and defines the special action to use. The string jumpto denotes the special FlowStepAction de.schlund.pfixcore.workflow.FlowStepJumpToAction which is used to set the jumptopage (defined via the page attribute) and/or the jumptopageflow (defined via the pageflow attribute).

          </action>
        </when>
        <when test="A_XPath_Expression">
          <action type="A_FlowStepAction" somekey="somevalue">
      

If the type attribute is not jumpto, the value is interpreted as a class of type de.schlund.pfixcore.workflow.FlowStepAction. There can be an arbitrary number of additional attributes (somekey in this example) which are supplied as named parameters to the special FlowStepAction.

          </action>
        </when>
      </oncontinue>
    </flowstep>
  </pageflow>
  
  <pagerequest name="APageName" nostore="true|false" copyfrom="APageName">
      

Attribute Description
name Mandatory. It must be the name of a page defined in the corresponding depend.xml file.
nostore Optional. If given, and set to true makes the page a so called sidestep page. This has the consequence that the resulting DOM tree is not stored in the session (so no frames are possible!) and that the status of the Context object (current page, current pageflow) isn't changed. The use of this feature is to allow for pages to act as e.g. CSS or JavaScript without disturbing the flow of the main pages. See also the section about properties below.
copyfrom Optional. If given, and set to the name of a valid pagerequest, all configuration from this referenced pagerequest are used for the current page, disregarding all configuration that is made in this pagerequest. It's a plain and simple copy, no extending, no restricting!

    <ssl force="true|false"/>
      

The node is optional. If given, and the attribute force is set to true, the page will only run under SSL when jumped to via a link or a submit of form data. If the session currently does not run under SSL, the system will make sure to redirect to a secure session prior to handling the request. After a session is running under SSL, there is no way back (so all other pages will run securely regardless if they have a ssl node or not). You can wrap this tag within a customization element to force use of SSL only in certain modes (e.g. prod mode).

[Note]Note

You can force the servlet as a whole to run only under SSL by specifying the ssl subnode of the servletinfo node.

<state class="AClassName"/>
      

The whole node is optional. If given, the class attribute must be the name of a java class implementing the de.schlund.pfixcore.workflow.State interface. The used State is determined as follows:

  1. If state is given, use the value of it's class attribute. Else:

  2. If the pagerequest has a auth child, use de.schlund.pfixcore.workflow.app.DefaultAuthIWrapperState. Else:

  3. If the pagerequest has an input child, use the value of the class attribute of the defaultihandlerstate tag explained above if it is given. If this is not given, just use de.schlund.pfixcore.workflow.app.DefaultIWrapperState. Else:

  4. use the value of the class attribute of the defaultstate tag explained above if it is given. If this is not given, just use de.schlund.pfixcore.workflow.app.StaticState.

You can use any BSF-supported scripting language for writing your State-implementation, too. See PustefixScripting for details on how to do this.

    <finalizer class="AClassName"/>
      

The whole node is optional. It may only be given for a State that is either de.schlund.pfixcore.workflow.app.DefaultIWrapperState or a descendent of it. The class attribute is mandatory and denotes a class implementing de.schlund.pfixcore.workflow.app.ResdocFinalizer.

[Caution]Caution

The use of finalizers is not suggested most of the time! They can completely change the result document and the logic when to trigger the next step in the current page flow. Use them at your own risk. Or better: Don't use them at all.

    <input policy="ANY|ALL|NONE">
      

The whole node is optional. It may only be given for a State that is either de.schlund.pfixcore.workflow.app.DefaultIWrapperState or a descendent of it! policy is optional (default is ANY). The policy decides when a whole page is considered to be accessible:

  • ANY: just one of the associated handlers needs to be active for the page to be accessible.

  • ALL: all the associated handlers must be active for the page to be accessible.

  • NONE: none of the associated handlers needs to be active for the page to be accessible.

If one of the associated handlers returns false on calling prerequisitesMet(), the page is of course still inaccessible.

      <interface prefix="AName" class="AClassName" activeignore="true|false" continue="true|false" alwaysretrieve="true|false"/>
      

There can be many interface nodes for a page. Each one references an "atomic" functional entity consisting of an IWrapper java class (usually autogenerated from a .iwrp xml file, see here) that defines the type and names of the parameters passed between the UI and the functional entity and an associated IHandler java class that uses the IWrapper to retrieve the passed parameters via typed getter methods.

Attribute Description
prefix Mandatory. The prefix defines a name for the IWrapper and in effect a namespace for the IWrapper's parameters. If the prefix "bar" is defined for an IWrapper that contains a parameter called "Foo", the submitted HTTP parameter must be called bar.Foo.
class Mandatory. Must be the name of a java class implementing de.schlund.pfixcore.generator.IWrapper. This implicitly defines a de.schlund.pfixcore.generator.IHandler, as every IWrapper knows it's associated IHandler and can be queried for it.
continue Optional, defaults to false. If the user submits data usually all defined handlers are called. If the submit doesn't result in errors, the usual action is that the context will switch to the next page according to the current pageflow. This is different when the submit is restricted to a subset of one ore more of the page's defined handlers. The usual action in this case is to stay on the page no matter if the data submit was successful (no errors happened) or not. BUT: if ALL of the handlers the submit was restricted to have the attribute continue set to true, the context again will switch to the next page.
activeignore Optional, default is false. The IHandler method isActive() is NOT called on handlers with activeignore set to true. In other words: the handler is ignored when the system tries to find out if the page is accessible or not. See also the comment for the policy attribute above.
alwaysretrieve Optional, default is false. This attribute changes the way the not selected IHandlers of a page are treated when the system decides that it should stay on the page after a submit has been handled without an error. The default behaviour is to only call retrieveCurrentStatus() on those IHandlers that are in the set of selected (via the SELWRP command) IHandlers. For the remaining IHandlers, only the (ignored) input is copied back verbatim so the net effect is that all associated form elements stay the same as they were before the submit. By setting alwaysretrieve to true the retrieveCurrentStatus() method of this IHandler is also called in the described situation. You need this if a submit handled in one or more IHandler(s) should change the filled-in form values of another, not currently selected IHandler.

    </input>
      

[Caution]Caution

Only one of input or auth may be given as a child node!

    <auth>
      

The whole node is optional. It may only be given for a page using a State that is either de.schlund.pfixcore.workflow.app.DefaultAuthIWrapperState or a descendent of it! There may be only one pagerequest using such a State, it must be the one that is also referred to via the authpage attribute of the context node above. Other pagerequest nodes must not have this subnode!

      <authinterface prefix="AName" class="AClassName"/>
      <auxinterface prefix="AName" class="AClassName"/>
      

One and only one authinterface node must be given. auxinterface nodes are optional and can be given multiple times. The prefix and class attributes are mandatory for both nodes. The meaning is the same as for the interface subnodes of the ihandler node. The authinterface node denotes the one IWrapper/IHandler combo that is responsible for checking the authentification of a user session. The auxinterface nodes denote additional IWrappers/IHandlers that are called after the authentification handler if the authorization is granted. Note that no error handling whatsoever takes place for auxinterface IHandlers.

    </auth>
    
    <output>
      

The whole node is optional. Every page using a State that is itself or a descendant of de.schlund.pfixcore.workflow.app.StaticState can use this. You can have as many resource childnodes as you like.

      <resource node="AName" class="AClassName"/>
      

Attribute Description
class Mandatory. class is one of the ContextResources defined via implements above.
node Mandatory. node is the node in the output tree ("/formresult/AName") under which the ContextResource inserts it's data.

    </output>
    
    <properties>
      

The whole node is optional.

      <prop name="APropertyKey">AValue</prop>
      

The node is mandatory and can be used multiple times. It will be transformed into a java property that is associated to the page. There are some props that are already defined for de.schlund.pfixcore.workflow.app.StaticState and descendants. These are listed below

Property Name Property Value Description
mimetype e.g. text/css If given, sets the mimetype of the HttpResponse object to something else than the default text/html. This is most often used for text/css.
responseheader.A_HEADER A_VALUE If given, set the header A_HEADER of the HttpResponse object to A_VALUE. NOTE: the Pustefix system uses a set of default headers that are only used, when no user defined headers are given! The set of default headers is: Expires=Mon, 26 Jul 1997 05:00:00 GMT Cache-Control=private If you want to use some of them in addition to your own headers, you must manually supply them, too.

    </properties>
  </pagerequest>
  
  <config-include file="myproject/conf/myfile.xml" section="pagerequests"/>
      

Includes a part of a config fragments file at this location. See Section 1.4, “Configuration fragments file format” for details on how to define config fragments.

Attribute Description
file Mandatory. Path to the file that contains the tags to be included (relative to docroot).
section Optional. Type of the section that shall be included. If more than one section of the specified type exists in the file, the content of all this sections is included.
refid Optional. Include a section identified by the specified id. The refid specified here must match the id attribute of exactly one section in the specified file.
xpath Optional. A XPath expression specifying the node-set to be included. The prefixes to be used for XML namespaces are "fr" for the namespace of the fragments file tags and "pr" for the namespace of the ContextXMLServlet configuration tags.

One and only one of the section, refid or xpath attribute has to be specified for each config-include.

  <properties>
    <prop name="AProperty">AValue</prop>
      

Property Name Property Value Description
mimetype e.g. text/css If given, sets the mimetype of the HttpResponse object to something else than the default text/html. This is most often used for text/css.
responseheader.A_HEADER A_VALUE If given, set the header A_HEADER of the HttpResponse object to A_VALUE. Headers set here can be overwritten for specific pages. NOTE: the Pustefix system uses a set of default headers that are only used, when no user defined headers are given! The set of default headers is: Expires=Mon, 26 Jul 1997 05:00:00 GMT Cache-Control=private If you want to use some of them in addition to your own headers, you must manually supply them, too.

You can also specify properties here that are understood by the ServletManager class.

  </properties>
</contextxmlserver>
      

1.3. DirectOutputServlet

Occasionally you don't want to generate output with an XSLT Transformation, but e.g. deliver binary content directly to the output stream instead. In this case you need to provide another servlet of type de.schlund.pfixxml.DirectOutputServlet. This servlet doesn't have it's own Context object but instead "hijacks" the Context of a foreign de.schlund.pfixxml.ContextXMLServlet. The context isn't used for any pageflow handling, only as a means to get to the data (via its ContextResources) of the "main" application.

The servlet knows about one or many directoutputpagerequests. For the XML/XSLT side of things, they look like normal pages (in fact, the value of the directoutputpagerequest's name attribute must be a page defined in depened.xml. Of course, no target definition has to be given, only the page in the navigation structure must exist). But other than the usual pagerequest, a directoutputpagerequest has an associated directoutputstate whose class attribute is a java class implementing de.schlund.pfixcore.workflow.app.DirectOutputState.

<directoutputserver version="1.0"
  xmlns="http://pustefix.sourceforge.net/2004/properties"
  xmlns:cus="http://www.schlund.de/pustefix/customize"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://pustefix.sourceforge.net/2004/properties http://pustefix.sourceforge.net/2004/properties.xsd">
  
  <directoutputservletinfo depend="MyProject/conf/depend.xml" name="AUniqueNameForTheServlet">
    <ssl force="true|false"/>
    <editmode allow="true|false"/>
      

See the comment for the servletinfo node in Section 1.2, “ContextXMLServlet configuration format”.

  </directoutputservletinfo>
  
  <foreigncontext externalservletname="UniqueNameOfAnotherServlet" synchronized="true"/>
       

The externalservletname must reference the name of a servlet of type de.schlund.pfixxml.ContextXMLServlet. The Context (or better: the ContextResourceManager) of this servlet is used for getting stored application data. Additionally, if the ContextXMLServlet requires authentication, it's authentication page is checked before any DirectOutputState is called. The synchronized attribute is optional. It defaults to true. If set to true, only one request per session is handled concurrently. If set to false all requests will be handled concurrently, requiring thread-safe business logic.

  <config-include file="myproject/conf/myfile.xml" section="directoutputpagerequests"/>
       

Includes a part of a config-fragments at this location. See Section 1.4, “Configuration fragments file format” for details on how to define config fragments.

Attribute Description
file Mandatory. Path to the file that contains the tags to be included (relative to docroot).
section Optional. Type of the section that shall be included. If more than one section of the specified type exists in the file, the content of all this sections is included. For a DirectOutputServlet configuration only directoutputpagerequests and properties are valid.
refid Optional. Include a section identified by the specified id. The refid specified here must match the id attribute of exactly one section in the specified file.
xpath Optional. A XPath expression specifying the node-set to be included. The prefixes to be used for XML namespaces are "fr" for the namespace of the fragments file tags and "pr" for the namespace of the DirectOutputServlet configuration tags.

One and only one of the section, refid or xpath attribute has to be specified for each config-include.

  <directoutputpagerequest name="APageName">
    <directoutputstate class="AClassName"/>
    <properties>
      

The whole properties node is optional.

      <prop name="APropertyKey">AValue</prop>
      

The node is mandatory and can be used multiple times. It will be transformed into a java property that is associated to the page. The java property that is constructed will look like this: pagerequest.APpageName.APropertyKey=AValue where APageName is the value of the name attribute.

    </properties>
  </directoutputpagerequest>
</directoutputserver>
      

1.4. Configuration fragments file format

Configuration fragments files contain aggregated configuration directives that are intended to be reused in different configuration files.

<fr:config-fragments
  xmlns:fr="http://pustefix.sourceforge.net/configfragments200609"
  xmlns:pr="http://pustefix.sourceforge.net/properties200401"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://pustefix.sourceforge.net/configfragments200609 http://pustefix.sourceforge.net/configfragments200609.xsd">
  
  <fr:navigation id="nav1">
      

All sections have an optional id that can be used to identifiy the section when more than one section fo the same type is present in one file. The value of the id attribute has to be unique within the whole file.

    <page name="MyPage" handler="/xml/myhandler"/>
      

The structure here is the same as within the navigation tag of the depend.xml file.

  </fr:navigation>
  <fr:targets>
    <standardpage name="MyPage" xml="myproject/xml/mymaster.xml"/>
      

The tags allowed here are the same that are allowed for standardpage or target definitions in the depend.xml file.

  </fr:targets>
  <fr:resources>
    <pr:resource class="com.example.MyResourceImpl">
      <pr:implements class="com.example.MyResource"/>
    </pr:resource>
      

The tags allowed here are the same that are allowed for the definition of context resources within the context tag of the ContextXMLServlet configuration.

  </fr:resources>
  <fr:interceptors>
    <pr:interceptor class="com.example.MyInterceptor"/>
      

The tags allowed here are the same that are allowed within the startinterceptors and endinterceptors tags of the ContextXMLServlet configuration.

  </fr:interceptors>
  <fr:scriptedflows>
    <pr:scriptedflow name="myscript" file="myproject/conf/scriptedflows/myscript.script.xml"/>
      

The tags allowed here are the same that are allowed within the scriptedflows tag of the ContextXMLServlet configuration.

  </fr:scriptedflows>
  <fr:roles>
    <pr:role name="MY_ROLE">
      <pr:pageaccess names="mypage*"/>
    </pr:role>
      

The tags allowed here are the same that are used for role definition in the ContextXMLServlet configuration.

  </fr:roles>
  <fr:pageflows>
    <pr:pageflow name="MyFlow">
      <pr:flowstep name="MyFirstPage"/>
      <pr:flowstep name="MySecondPage"/>
    </pr:pageflow>
      

The tags allowed here are the same that are used for the definition of pageflows in the ContextXMLServlet configuration.

  </fr:pageflows>
  <fr:pagerequests>
    <pr:pagerequest name="MyPage"/>
      

The tags allowed here are the same that are used for the definition of pagerequets in the ContextXMLServlet configuration.

  </fr:pagerequests>
  <fr:properties>
    <pr:prop name="myproperty">myvalue</pr:prop>
      

The tags allowed here are the same that are allowed within the properties tag of the ContextXMLServlet configuration.

  </fr:properties>
  <fr:directoutputpagerequests>
    <pr:directoutputpagerequest name="foo">...</pr:directoutputpagerequest>
      

Direct output pagerequests can be defined here. See Section 1.3, “DirectOutputServlet” for details on this.

  </fr:directoutputpagerequests>
</fr:config-fragments>
      

1.5. FactoryInitServlet (factory.xml)

This property file is located in projects/common/conf/factory.xml and used by the de.schlund.pfixxml.FactoryInitServlet servlet (contained in the special admin project used in every Pustefix environment) whenever the servletcontainer starts up to initialize services that are used by all the other projects. The syntax of this file is described in Section 1.1, “Java property files in Pustefix”.

1.6. Global properties (pustefix.xml)

The syntax of the common/conf/pustefix.xml file complies to the description in Section 1.1, “Java property files in Pustefix”. The properties defined here are merged with the properties defined for a specific servlet. However, there are some properties with a special meaning.

Exception processing is configured via prop elements whose names comply to following syntax: exception.TYPE.[page|forward|processor] For one single TYPE, there may be only one occurrence of page, forward and processor.

TYPE is a fully qualified class name of a valid exception class, for which the handling should be configured at this point. In this case it specifically means, that the specified class must be a descendant of java.lang.Throwable, as the catch-block that handles the exceptions which are specified here, catches Throwable.

If an exception occurs during exception processing, or during processing of the page the request got forwarded to, no further exception handling will take place. Therefore the code that processes exceptions and the code that drives pages to which requests get forwarded, in case of exceptions, should be robust. Otherwise the whole exception-handling thing would be quite useless, wouldn't it?

Table 1.1. Exception processor properties
Attribute Description
file Mandatory. Path to the file that contains the tags to be included (relative to docroot).
section Optional. Type of the section that shall be included. If more than one section of the specified type exists in the file, the content of all this sections is included. For a DirectOutputServlet configuration only directoutputpagerequests and properties are valid.
refid Optional. Include a section identified by the specified id. The refid specified here must match the id attribute of exactly one section in the specified file.
xpath Optional. A XPath expression specifying the node-set to be included. The prefixes to be used for XML namespaces are "fr" for the namespace of the fragments file tags and "pr" for the namespace of the DirectOutputServlet configuration tags.

Chapter 2. Advanced topics

2.1. Role-based authorization

Pustefix provides a role-based authorization mechanism. You can define arbitrary roles, declare logical operations/combinations on this roles using authconstraints, and assign these authconstraints to pagerequests.

A role is defined using an according XML element with a unique name attribute value. Setting the initial attribute to true the role will be automatically set on context initialization.

  <role name="MYROLE" initial="true"/>

Authconstraints can combine various authorization conditions, supported conditions are: hasrole, and, or and not, represented by according XML elements. Using the authpage attribute you can define the page, which should be called on authorization failure. Using the default attribute you can set one toplevel authconstraint to be the default one for all pagerequests having no authconstraint asssigned.

  <authconstraint id="MYCONSTRAINT" authpage="login" default="true">
    <or>
      <hasrole name="MYROLE"/>
      <hasrole name="OTHERROLE"/>
    </or>
  </authconstraint>

Pagerequests can either define new authconstraints as child elements or can reference existing toplevel authconstraints by their id.

  <pagerequest name="mypage">
    <authconstraint ref="MYCONSTRAINT"/>
    ...
  </pagerequest>

  <pagerequest name="mypage">
    <authconstraint authpage="login">
      <hasrole name="MYROLE"/>
    </authconstraint>
    ...
  </pagerequest>

You can programmatically set/query roles using the de.schlund.pfixcore.auth.Authentication object, which can be retrieved from the Context calling its getAuthentication() method.

public interface Authentication {
    
    public boolean hasRole(String roleName);
    public boolean addRole(String roleName);
    public boolean revokeRole(String roleName);
    
    public Role[] getRoles();
    
}

You can add a new role using addRole(), revoke exisiting roles using revokeRole() or check for a role using hasRole(). Using getRoles() you get an array of all currently set roles. If a default role is defined, this role will be initially set.

You can also query the current roles from within your XML/XSLT code using the XPath extension function pfx:hasRole(rolename)

      <ixsl:if test="pfx:hasRole('MYROLE')">
         ...
      </ixsl:if>
    

If you try to access a page for which the authconstraint isn't fulfilled, you're forwarded to the according login page. The login page has to be a regular page, i.e. IWrappers on the page are configured the regular way (no authinterface elements). Login forms require the type attribute set to roleauth (instead of auth in the traditional login forms).

    <pfx:forminput type="roleauth">
      ...
    </pfx:forminput>
    

The framework automatically inserts an authentication element into the login page's DOM tree. This element contains the state of the authenticated flag, the targetpage which should be accessed, the current roles and the authorizationfailure containing the violated authconstraint.

    <formresult>
      <authentication authenticated="true" targetpage="mypage">
        <roles>
          <role name="SOMEROLE"/>
        </roles>
        <authorizationfailure authorization="pageaccess" target="mypage">
          <authconstraint>
            <hasrole name="MYROLE"/>
          </authconstraint>
        </authorizationfailure>
      </authentication>
      ...
    </formresult>
    

Example

The following example defines three roles. The role ANONYMOUS is configured as initial role, i.e. every session/context has this role automatically set from the beginning.

There are two top-level authconstraints. The authconstraint AC_DEFAULT is declared as default, i.e. pages, having no explicitly set authconstraint, will get this one. The authconstraint's authpage is set to login and it has a simple condition saying that it requires the role ANONYMOUS.

The authconstraint AC_KNOWN declares that it requires the USER or the ADMIN role. This authconstraint is referenced by the pagerequest userpage, using an empty authconstraint element having a ref attribute containing the authconstraint's id.

The pagerequest adminpage contains an anonymous authconstraint element, which defines the role ADMIN as requirement.

<contextxmlserver>
  
  <role name="ANONYMOUS" initial="true"/>
  <role name="USER"/>
  <role name="ADMIN"/>
  
  <authconstraint id="AC_DEFAULT" authpage="login" default="true">
    <hasrole name="ANONYMOUS"/>
  </authconstraint>
  
  <authconstraint id="AC_KNOWN" authpage="login">
    <or>
      <hasrole name="USER"/>
      <hasrole name="ADMIN"/>
    </or>
  </authconstraint>
  
  <pagerequest name="home">
    ...
  </pagerequest>
  
  <pagerequest name="login">
    <input>
      ...
    </input>
  </pagerequest>

  <pagerequest name="adminpage">
    <authconstraint authpage="login">
      <hasrole name="ADMIN"/>
    </authconstraint>
    ...
  </pagerequest>
  
  <pagerequest name="userpage">
    <authconstraint ref="AC_KNOWN"/>
    ...
  </pagerequest>

  ...

</contextxmlserver>

2.2. Object-to-XML mapping

Pustefix provides a lightweight object serialization mechanism, which can be used to serialize arbitrary objects into the result DOM without having to do any DOM operations by yourself. The XML binding is customizable via Java annotations within the bean classes.

The framework supports arbitrary Beans, Arrays, Collections, Maps, Numbers (including the primitive types and their object wrapper types), Strings, and Date/Calendar. To support other types or to serialize to a custom format, it's possible to write your own serializers and annotations (to attach them to the according bean properties).

The serialization of beans can be customized using the generic Pustefix bean annotations, which are known from the JSON serialization framework. You can exclude individual properties from serialization by marking the according getter with an @Exclude annotation or you can exclude all properties by marking the bean class with an @ExcludeByDefault annotation and include individual properties with @Include annotations at their getters (marking public members is supported too). Using the @Alias annotation you can control the name used as the resulting attribute or element name.

The serialization to the result tree is done by calling one of the static addObject methods of the ResultDocument class. The element argument is the parent DOM element at which the serialized XML will be appended, the optional name argument can be used to create an additional child element for the serialized XML. The object argument is the object, which should be serialized.

	   public class ResultDocument {
	     ...
	     public static Element addObject(Element element, Object object) {...}
	     public static Element addObject(Element element, String name, Object object) {...}
	   }
	  

Serialization process

The default serialization process tries to produce relatively compact XML. Thus it favours attributes over elements and serializes so-called simple types, which can be represented as strings, into attributes where it's possible and makes sense, e.g. for bean properties.

Let's look at an example, which shows the serialization of a simple bean using bean and serializer annotations to customize the serialization behaviour:

        ...
	  
        public class Account {
  
          private long accountNo;
          private float debit;
          ...
  
          public long getAccountNo() {
            return accountNo;
          }

          public void setAccountNo(long accountNo) {
            this.accountNo = accountNo;
          }

          @Alias("balance")
          public float getDebit() {
            return debit;
          }

          public void setDebit(float debit) {
            this.debit = debit;
          }
  
          public Currency getCurrency() {
            return currency;
          }
  
          public void setCurrency(Currency currency) {
            this.currency = currency;
          }
  
          @DateSerializer("yyyy-MM-dd HH:mm:ss")
          public Calendar getOpeningDate() {
            return openingDate;
          }

          public void setOpeningDate(Calendar openingDate) {
            this.openingDate = openingDate;
          }
  
          @Exclude
          public String getComment() {
            return comment;
          }

          public void setComment(String comment) {
            this.comment = comment;
          }

        }
	  

Here you see how the bean's serialized to the ResultDocument within a ContextResource:

        ...
        
        public class ContextAccountImpl implements ContextAccount {

          private Account account;
	      ...
	
          public void insertStatus(ResultDocument resdoc, Element elem) throws Exception {
            ResultDocument.addObject(elem,"account",account);
          }
          
        }
      

The resulting DOM fragment looks like this:

        <formresult serial="1199439160721">
          ...
          <data>
            <account accountNo="2000123" currency="EUR" balance="332.54" openingDate="2003-11-04 09:15:38"/>
          </data>
          ...
        </formresult>
      

The data element is the ContextResource's root node as configured in the configuration file. Calling addObject with the additional account argument, the serialized bean isn't added directly to the data element, but an additional element is used. The bean's properties are serialized as attributes of this element.

The debit property is renamed to balance using the @Alias annotation. The comment property is excluded using the @Exclude annotation. The openingDate property is serialized using the built-in DateSerializer, which can be customized using the @DateSerializer annotation. Thus you can provide your own date format pattern (must be a pattern supported by java.text.SimpleDateFormat).

Only simple type properties, i.e. properties which can be serialized to string values, can be represented as attributes. If the Account bean would have an additional property customer of a bean type, e.g. a Customer class, this property would be serialized as a child element:

        <formresult serial="1199439160721">
          ...
          <data>
            <account accountNo="2000123" balance="EUR" debit="332.54" openingDate="2003-11-04 09:15:38">
              <customer customerId="100000" firstName="Mike" lastName="Foo"/>
            </account>
          </data>
          ...
        </formresult>
      

Collections and Arrays are represented using an element for each entry. The element name is derived from the the simple name of the entry's class (without package name and starting lowercase):

        <formresult serial="1199439160721">
          ...
          <data>
            <account accountNo="2000000" currency="EUR" balance="3124.49" openingDate="2003-10-23 08:05:10"/>
            <account accountNo="2000123" currency="EUR" balance="332.54" openingDate="2003-11-04 09:15:38"/>
            <account accountNo="2001405" currency="EUR" balance="25123.11" openingDate="2005-01-13 10:10:10"/>
          </data>
          ...
        </formresult>
      

The element name can be changed using the @ClassNameAlias annotation, e.g. to rename the account element to bankaccount:

      @ClassNameAlias("bankaccount")
      public class Account {
        ...
      }
      

Maps are represented using an entry element for each map entry. Key and value are represented by child elements (whereas the element names are derived from the class names):

        <formresult serial="1199439160721">
          ...
          <data>
            <entry>
              <long>2000000</long>
              <account accountNo="2000000" currency="EUR" debit="3124.49" openingDate="2003-10-23 08:05:34"/>
            </entry>
            <entry>
              <key>2001405</key>
              <account accountNo="2001405" currency="EUR" debit="25123.11" openingDate="2005-01-13 10:10:34"/>
            </entry>
            <entry>
              <key>2000123</key>
              <account accountNo="2000123" currency="EUR" debit="332.54" openingDate="2003-11-04 09:15:34"/>
            </entry>
          </data>
          ...
        </formresult>
      

Circular object references are handled by adding a xpathref attribute to the according element. Its value is an absolute XPath expression referencing the according object's element:

      <formresult serial="1199702214819">
        ...
        <data>
          <account accountNo="2000123">
            <customer customerId="100000">
              <accounts>
                <account accountNo="2000000">
                  <customer xpathref="/formresult/data[1]/account[1]/customer[1]"/>
                </account>
                <account xpathref="/formresult/data[1]/account[1]"/>
                <account accountNo="2001405">
                  <customer xpathref="/formresult/data[1]/account[1]/customer[1]"/>
                </account>
              </accounts>
            </customer>
          </account>
        </data>
        ...
      </formresult>
      

In this example the Account bean has a reference to a Customer bean, which itself has a reference to all of its Accounts. You can see that all beans, which were already serialized (as ancestors in the tree) contain an according back-reference.

Strings that contain XML code can be inserted as XML fragment the the resulting document by using the @XMLFragmentSerializer:

        public class FragmentBean {

            private String myFragment = "<foo><bar baz=\"true\"/>character data</foo>";

            @XMLFragmentSerializer
            public String getMyFragment() {
                return myFragment;
            }
        }
      

The XML, that is returned by the getMyFragment method is not treated as a simple string, but as an XML fragment and thus, the content is not escaped, when inserted in the document:

        <?xml version="1.0" encoding="utf-8"?>
        <result>
           <myFragment>
              <foo>
                 <bar baz="true"/>character data</foo>
           </myFragment>
        </result>
      

Custom serializers

If you don't like the default serialization mechanism or you use unsupported types, you can write your own serializers. There are two types of serializers: SimpleTypeSerializers, which can produce String values (e.g. for primitive types), and ComplexTypeSerializers, which can produce structured XML data (e.g. for bean types).

Implementing your own serializer just requires to implement the SimpleTypeSerializer or ComplexTypeSerializer interface and create a custom annotation to be able to attach your serializer to a bean property.

Let's look at an example of a SimpleTypeSerializer: a custom String serializer, which allows to configure if Strings should be ouput lower- or uppercase. Here's the implementation:

        ...
        import de.schlund.pfixcore.oxm.impl.AnnotationAware;
        import de.schlund.pfixcore.oxm.impl.SimpleTypeSerializer;
        import de.schlund.pfixcore.oxm.impl.annotation.StringSerializer;
        ...

        public class StringTypeSerializer implements SimpleTypeSerializer, AnnotationAware {

          private boolean doLowerCase;
	
          public void setAnnotation(Annotation annotation) {
            StringSerializer s=(StringSerializer)annotation;
            doLowerCase=s.value();
          }
		
          public String serialize(Object obj, SerializationContext context) throws SerializationException {
            if(obj instanceof String) {
              String str=(String)obj;
              if(doLowerCase) str=str.toLowerCase();
              else str=str.toUpperCase();
              return str;
            } 
            throw new SerializationException("Illegal type: "+obj.getClass().getName());
          }
        }
      

The serializer implements the SimpleTypeSerializer interface. Its serialize method checks if the passed object is of type String and calls toLowerCase or toUpperCase before returning the new String. The doLowerCase property controls which method is used. This property is set within the setAnnotation method. The method is defined in the AnnotationAware interface. This method is called by the framework after the serializer is instantiated and passes the annotation set at the according bean property. So you can access the configured values and configure your serializer. Let's look at the according annotation definition:

        ...
        
        @SimpleTypeSerializerClass(StringTypeSerializer.class)
        @Target({ElementType.METHOD,ElementType.FIELD})
        @Retention(RetentionPolicy.RUNTIME)
        public @interface StringSerializer {
          boolean value();
        }
      

You have to annotate the custom annotation with a SimpleTypeSerializerClass annotation with the serializer class as value, make the annotation available to methods and fields using the @Target annotation and make it visible at runtime using the @Retention annotation. The rest of the annotation definition can be done according to your needs. In the example we just define a boolean property indicating if the String should be converted to lower- or uppercase. Here you see how the annotation is applied to serialize a customer's lastname as uppercase:

      public class Customer {
        ...
        @StringSerializer(false)
        public String getLastName() {...}
      }
      

Let's look at an example of a ComplexTypeSerializer. We want to customize the serialization of a Customer bean: the firstName and lastName properties should be output together within a name element:

      public class Customer {
        ...
        public long getCustomerId() {...}
        public String getFirsstName() {...}
        public String getLastName() {...}
        public List<Account> getAccounts() {...}
        ...
      }
      

The serializer just implements ComplexTypeSerializer. We don't need to implement AnnotationAware because our annotation will have no parameter we may want to read:

      public class CustomerTypeSerializer implements ComplexTypeSerializer {

        public void serialize(Object obj, SerializationContext context, XMLWriter writer) throws SerializationException {
          if(obj instanceof Customer) {
            Customer customer=(Customer)obj;
            writer.writeStartElement("name");
            writer.writeCharacters(customer.getFirstName()+" "+customer.getLastName());
            writer.writeEndElement("name");
            context.serialize(customer.getAccounts(),writer);
          } else throw new SerializationException("Illegal type: "+obj.getClass().getName());
        }
       
      }
      

The serialize method gets a XMLWriter object, which is used to write the name element. Then the passed SerializationContext is used to serialize the customer's accounts using the default serialization mechanism.

Finally we implement a custom annotation:

      @ComplexTypeSerializerClass(de.schlund.pfixcore.example.bank.oxm.CustomerTypeSerializer.class)
      @Target({ElementType.METHOD,ElementType.FIELD})
      @Retention(RetentionPolicy.RUNTIME)
      public @interface CustomerSerializer {}
	  

Here we apply the annotation to the Account bean's customer property:

      public class Account {
        ...
        @CustomerSerializer
        public Customer getCustomer() {...}
        ...
      }
      

Here's an excerpt of the resulting XML:

      <formresult serial="1199705488403">
        ...
        <data>
          <account accountNo="2000000" balance="3124.49" currency="EUR" openingDate="2003-10-23 08:05:22">
            <customer>
              <name>Mike Foo</name>
              <account accountNo="..."/>
              <account accountNo="..."/>
              ...
            </customer>
          </account>
        </data>
        ...
      </formresult>
      

2.3. Annotation-based IWrapper creation

The annotation-based IWrapper creation provides an alternative to the usual, XML configuration based, IWrapper creation. Using this approach you create IWrappers from standard Java Beans by adding the necessary configuration data in the form of annotations.

The IWrappers are automatically created during the build process using the Sun JVM's apt tool and a custom AnnotationProcessor which analyzes the Java bean's source code and generates the according IWrapper sources.

You're making a bean to a template for an IWrapper by adding an @IWrapper annotation to its class declaration. By default every bean property that is of a so-called builtin type, i.e. has a pre-defined IWrapperParamCaster implementation, will be automatically added as an IWrapper parameter.

Builtin types are boolean, byte, double, float, int, long, java.lang.Boolean, java.lang.Byte, java.lang.Double, java.lang.Float, java.lang.Integer, java.lang.Long, java.lang.String, java.util.Date and Arrays with components of these types.

Bean properties of an unknown type are either ignored or require a @Caster annotation specifying an appropriate caster. Bean properties can be annotated at their getter methods or at the field itself, if it's public. If a property of a builtin type should be skipped you can mark the according property with a @Transient annotation.

Bean based IWrappers can be used to create new beans or fill existing beans with the IWrapper's state. Therefore the IWrapperToBean class provides the two static methods <T> T createBean(IWrapper wrapper, Class<T> beanClass) and populateBean(IWrapper wrapper, Object obj).

IWrapper annotations

Every IWrapper configuration element known from the XML configuration has an annotation counterpart. Besides there are some special annotations like @IWrapper and @Transient. In the following we'll give a short overview of all avaible annotations:

        @Target(ElementType.TYPE)
        @Retention(RetentionPolicy.RUNTIME)
        public @interface IWrapper {
          String name() default "";
          Class<? extends IHandler> ihandler() default IHandler.class;
        }
        
        @IWrapper(name="MyBeanWrapper",ihandler=MyBeanHandler.class)
        public class MyBean {
          ...
        }
      

The @IWrapper annotation is used to mark a class as template for an IWrapper. The name attribute denotes the class name of the generated IWrapper class (without package). By default the bean name with the suffix Wrapper is used (and the same package). The ihandler attribute denotes the IHandler implementation class.

        @Target({ElementType.METHOD,ElementType.FIELD})
        @Retention(RetentionPolicy.RUNTIME)
        public @interface Param {
          String name() default "";
          boolean mandatory() default true;
          boolean trim() default true;
          String missingscode() default "";
          String[] defaults() default {};
        }
        
        @IWrapper(name="MyBeanWrapper",ihandler=MyBeanHandler.class)
        public class MyBean {
          ...
          @Param(name="MyValue",mandatory=false)
          public int getValue() {...}
        }
      

The @Param annotation is used to mark a bean property as parameter and configure its name and all the other options known from the IWrapper XML configuration. This annotation is optional, leaving it out, the property name is used as name and the other attributes are set to their default values.

        @Target({ElementType.METHOD,ElementType.FIELD})
        @Retention(RetentionPolicy.RUNTIME)
        public @interface Caster {
          Class<? extends IWrapperParamCaster> type();
          Property[] properties() default {};
        }
        
        @IWrapper(name="MyBeanWrapper",ihandler=MyBeanHandler.class)
        public class MyBean {
          ...
          @Caster(type=SomeClassCaster.class)
          public SomeClass getValue() {...}
        }
      

The @Caster annotation denotes the caster implementation class. The nested properties attribute can be used to set properties via @Property annotations. That's the same as the cparam elements in the XML configuration (the params/properties are set using according methods prefixed with put_).

        @Target({ElementType.METHOD,ElementType.FIELD})
        @Retention(RetentionPolicy.RUNTIME)
        public @interface Property {
          String name();
          String value();
        }
      

The @Property annotation is used as nested annotation within the properties array attribute of various annotations. It consists of simple name/value pairs.

        @Target({ElementType.METHOD,ElementType.FIELD})
        @Retention(RetentionPolicy.RUNTIME)
        public @interface PreCheck {
          Class<? extends IWrapperParamPreCheck> type();
          Property[] properties() default {};
        }
        
        @IWrapper(name="MyBeanWrapper",ihandler=MyBeanHandler.class)
        public class MyBean {
          ...
          @PreCheck(
            type=de.schlund.pfixcore.generator.prechecks.RegexpCheck.class,
            properties={
              @Property(name="regexp",value="/^(M|L|XL)$/")
            }
          )
          public String getValue() {...}
        }
      

The @PreCheck annotation denotes the precheck implementation class with optional properties/parameters.

        @Target({ElementType.METHOD,ElementType.FIELD})
        @Retention(RetentionPolicy.RUNTIME)
        public @interface PostCheck {
          Class<? extends IWrapperParamPostCheck> type();
          Property[] properties() default {};
        }
        
        @IWrapper(name="MyBeanWrapper",ihandler=MyBeanHandler.class)
        public class MyBean {
          ...
          @PostCheck(
            type=de.schlund.pfixcore.generator.postchecks.IntegerRange.class,
            properties={
              @Property(name="range",value="0:2")
            }
          )
          public int getValue() {...}
        }
      

The @PostCheck annotation denotes the postcheck implementation class with optional properties/parameters.

        @Target({ElementType.METHOD,ElementType.FIELD})
        @Retention(RetentionPolicy.RUNTIME)
        public @interface Transient {}
        
        @IWrapper(name="MyBeanWrapper",ihandler=MyBeanHandler.class)
        public class MyBean {
          ...
          @Transient
          public int getValue() {...}
        }
      

The @Transient annotation can be used to avoid that a bean property of a builtin type is made to an IWrapper parameter.

Chapter 3. Modules

Table of Contents

3.1. FireDebug
Usage

3.1. FireDebug

FireDebug is a JAVA implementation of FirePHP for Pustefix. It enables you to send log messages to Firefox and display them via FireBug. You can find more informations about FirePHP at http://www.firephp.org.

Usage

Adding the ContextResource

FireDebug is implemented as a ContextResource, so you can call it from everywhere within Pustefix as long as you have access to the Context.

<context defaultflow="DefaultFlow">
  <resource class="org.pustefixframework.util.firedebug.FireDebugImpl">
    <implements class="org.pustefixframework.util.firedebug.FireDebug" />
  </resource>
</context>

Log messages

To log messages just fetch the FireDebug ContextResource and call one of the different log methods.

FireDebug firePHP = (FireDebug) getContextResource(FireDebug.class);        
firePHP.log(a * b, "Multipliziere a(" + a + ") * b(" + b + ")");

Return the HTTP response headers

To set the needed response headers you have to use either the FireDebugEnabledState

<pagerequest name="Calculator">
  <state class="org.pustefixframework.util.firedebug.FireDebugEnabledState" />
</pagerequest>

or the FireDebugServletFilter or you can use both.

<servlet name="webservice">
  <active>true</active>
  <class>de.schlund.pfixcore.webservice.WebServiceServlet</class>
  <propfile>ajax-calculator/conf/webservice.conf.xml</propfile>
  <use-filter>FirePHPServletFilter</use-filter>
</servlet>