PTPortletFilter is actually a subclass of the more general ResponseFilter class, which also performs filtering of HTTP response text (not necessarily HTML) and has no dependency on the gatewaying of the HttpServletRequest. The PTPortletFilter modifies HTML line by line, meaning it operates on a single line of text at a time, rather than on the entirety of the HTML response. An exception to this rule is when an HTML tag extends across multiple lines, for example:
<a href="myapp/chooseLocale.faces" onclick="alert('Choose Locale');" >Choose Locale</a>
In this case, the PTPortletFilter will treat all the lines that the tag spans as a single line of HTML to be filtered.
The PTPortletFilter loads an XML configuration file on startup that defines the filter operations performed by the PTPortletFilter on the response HTML of the Web application being filtered. In addition to the filtering defined in that configuration file, the PTPortletFilter performs several other functions:
The filter configuration XML defines two sets of objects that can act on the response HTML: FilterAppenders and FilterOperations.
A FilterAppender is a Java class that appends HTML to the start and end of the response HTML. Since this operation is only performed once per request, it is more efficient to define a class to do this rather than using a FilterOperation to insert the HTML at the start and end of the response, since FilterOperations act on each and every line of the response HTML. Appenders are declared in the configuration XML file by referencing the class that generates the appender.
<httpfilter> <appenders> <appender class="com.plumtree.remote.filter.appender.AdaptivePortletAppender"/> </appenders> <operations> ... </operations> </httpfilter>
Appenders all call a single
init() function when instantiated that takes the FilterConfig of the PTPortletFilter as an argument. In this way the appender can access any initialization parameters that were set in the
web.xml where the filter was defined.
pt-portlet-java-[portletID]. This unique ID serves as the target HTML element every time the user initiates an in-place refresh request; the content within this <div> tag will be replaced by the response.
The second type of object defined by the PTPortletFilter configuration XML are the FilterOperation subclasses. Each FilterOperation subclass represents a specific text-processing operation that will be performed on each line of the text. FilterOperations are built into an operations tree, so that certain operations will take place only if the parent operation was successful in its operation. The following is a sample of the operations XML:
<operations> <grabtag> <tag>title</tag> <token>TITLE</token> </grabtag> <match> <pattern></?body[^>]*></pattern> <flags>i</flags> <operations> <grabattribute> <tag>body</tag> <attribute>onload</attribute> <token>BODYONLOAD</token> </grabattribute> <grabattribute> <tag>body</tag> <attribute>bgcolor</attribute> <token>BODYBGCOLOR</token> </grabattribute> <if> <token>BODYBGCOLOR</token> <exists/> <operations> <insert> <before><body[^>]*></before> <markup><div color=@BODYBGCOLOR@></markup> </insert> </operations> </if> <replace> <pattern><(/?)body</pattern> <with><$1div</with> <flags>i</flags> </replace> </operations> </match> ... </operations>
Several different types of FilterOperations are available. A filter operation functions by calling an
excecute method that takes two arguments: the next line of text from the HTTP response HTML, and a Map containing name/value pairs that can be used to replace tokens found. In the process of executing the operation, new values may be added or removed from the token Map, and the line of text may be altered before it is passed on to the next operation in the tree. Tokens are delimited by surrounding the token value name with the "@" character, as in
@TOKEN@. Tokens can be used in a variety of filter operation values and can also be used as variables to store data gleaned from processing the response HTML; for example a token can be created to store whether the response HTML used a
<title> tag or not. These token variables can also be subjected to conditional tests that can determine the flow of filter operations that act on a line of text.
Operations fall into three categories: text manipulation, conditional tests, and token setting.
The following operations can act on the text passed into the operation, and can pass an altered version of that text to the next operation. (Note: After clicking the links in the left columns of the tables below, you may need to refresh your browser to access the login page.)
|<replace>||The ReplaceOperation performs uses a regular expression pattern to match and replace text within a line of response HTML. The ReplaceOperation supports regexp back references and the use of tokens in both the pattern string and the replace string.|
|<insert>||InsertOperations can insert text anywhere in a line of HTML or can insert text before a numbered line of text. Special line number values for the start and end of the response HTML are "first" and "last." InsertOperations support the use of tokens both in any pattern string set and in the string to be inserted.|
|<delete>||DeleteOperations can be set up to delete a line of text from the response. Typically delete operations are only executed if some condition is satisfied.|
The following operations serve as gatekeepers in determining whether any suboperations are executed on the line of text. Conditional operations perform a conditional test on the line of response text and on token values. If the conditional test passes, then the suboperations of the conditional operation are executed.
|<match>||A MatchOperation will try to match a line of response text with a regular expression pattern. Any suboperations of the match pattern will act on each match found in the line of response text, not on the entire line of text itself. MatchOperations support back references and the use of tokens in the regular expression pattern.|
|<if>||Tests a line of text or token value to see if it meets a logical test. Some tests supported by IfOperations are "exists," "contains," and "equals." If the IfOperation test is successful, the suboperations of the IfOperation will be executed once on the entire line of text.|
Token Setting Operations
The following operations can extract values from the line of response text and set them as variables in the token Map.
|<set>||Sets a token value to the token Map. The value set by the SetOperation can contain token values.|
|<grab>||GrabOperations take the first string segment from the line of text that matches a regular expression pattern and sets it in the token Map.|
|<grabtag>||This operation will grab the inner HTML of an tag that does not span more than a single line. For example, the operation could grab the value between the <title> tags in the head of a document.|
|<grabattribute>||GrabAttributeOperations take an attribute value from a tag and set it in the token Map.|
|<graball>||Grabs the entire line of text and sets it in the token Map.|
|<delete>||Deletes a token value from the token Map.|
|<echo>||This operation will simple echo the contents of the tag whenever executed. Echoed messages will only show up in the logs if the logging level is set to "info" or "debug." Echo messages can contain token values.|
Creating Custom Filter Operations
Should developers want to perform an operation on the response HTML that is not addressed by the list of operations above, the PTPortletFilter supports the use of custom FilterOperation objects. To create a custom operation, developers must subclass the FilterOperation class and implement the
execute() method. In addition, developers may want to override the
init() method of the class to perform any initialization of the operation.
To declare a custom operation in the PTPortletFilter configuration XML file, developers will need to add the following XML to the file:
<httpfilter> <operations> ... <operation class="com.plumtree.remote.fitler.operations.MyCustomOperation"> <property name="property1">some value</property> <property name="property2">some other value</property> <operations> <set> <token>foo</token> <value>bar</value> </set> </operations> </operation> ... </operations> </httpfilter>
Note that any subclass of FilterOperation has support for suboperations built in, and the example above adds the
<set> operation of the custom operation
MyCustomOperation. However, since the execution of suboperations is often dependent on the successful execution of the parent operation, developers creating custom FilterOperations must make sure to call the
executeSubOperations() method in the
execute() method if they want to have the suboperations act on the response text.
Standard Token Values
The token Map passed into the FilterOperation.execute() method has several token values that are automatically set by the PTPortletFilter. In addition, the PTPortletFilter can be set so that all the values of a particular setting type (Admin, Community, Portlet, User, and so on) can be included in the token Map. In this way, the filter operations can refer to token values that are part of the preferences of the portlet being transformed by the PTPortletFilter.
The standard token values are the following:
|@LINE@||The current line number being processed by the filter operations.|
|@TEXT@||The original text of the line of response HTML that is currently being operated on.|
|@RESULT@||The result of the last operation on the text that was passed into it, usually a line of modified text from the HTTP response.|
|@PORTLETID@||The ID of the current portlet.|
|@COMMUNITYID@||The ID of the current community, if any.|
|@PAGEID@||The ID of the current page, if any.|
|@IMAGESERVER@||The URI or the portal imageserver.|
|@STYLESHEET@||The URL of the portal stylesheet.|
In addition, the developer can set init params in the
web.xml declaration of the PTPortletFilter that, if set to true, will include all the preferences for a particular settings type into the token Map. This allows portlet settings to govern the way a Web application is filtered. For example, a set of filter operations could be designed so that they only execute if they find a specific preference value in the token Map. These init param names are:
|admin.settings.tokens||Includes the Admin settings in the token Map if set to true.|
|community.settings.tokens||Includes the Community settings in the token Map if set to true.|
|communityportlet.settings.tokens||Includes the CommunityPortlet settings in the token Map if set to true.|
|portlet.settings.tokens||Includes the Portlet settings in the token Map if set to true.|
|user.settings.tokens||Includes the User settings in the token Map if set to true.|
|userinfo.settings.tokens||Includes the UserInfo settings in the token Map if set to true.|