MasonPlugin
This plugin allows to embed calls to
Mason
components within topics.
Description
Mason is a powerful tool for embeding Perl code in arbitrary text. It can be used to build sites with dynamic content or in any other context where dynamic texts are useful, especially html documents. The build blocks of a mason site are components. Each component can have its own initializazion code, receive arguments (that can be filled with a default value if missing), call another components, etc.
Build a complex and full featured site with mason is as easy as putting some micro components together. This power makes mason a good choice for interface design of web applications.
MasonPlugin allows to call mason components from within topics. This way it's possible to build web applications interface in a collaborative fashion, and more: join existing perl applications to TWiki.
The interface design is a critical point within the application development process. The consequences of a poor interface are disgusting: they can obfuscate a great application and make user's work harder or inefficient.
By definition users are the most qualified people to tell how the application interface should be. If there were an easy way they could take part of the interface design we would get better interfaces in shorter time.
Combining TWiki's simplicity and Mason's flexibility MasonPlugin turns the interface design process as easy and simple as editing topics and thus allows users to play around with the interfaces as much as their imagination permits.
Another interesting consequence is that this collaborative work is a great place for new ideas and feature requests, that is, the whole web application development process is potentially enhanced.
Besides enhanced interfaces the possibility of putting some application within TWiki is a great thing: It's possible to aggregate unlimited functionality to TWiki and get powerful integrated environments easily.
Syntax Rules
Components may be called by
%MASON{"/path/to/component" app="foo" args="var => 'val', list => [10, 5.2e-100, 'el3'], hash => {key1 => 'val1', key2 => 'val2'}" post_render="yes"}%, where:
-
"/path/to/component" is the component been called. Required.
-
app="foo" specifies which application to use, since it's possible to have more than one application available. Required, but see bellow.
-
args="..." passes arguments to the component. Optional, but see bellow.
-
post_render specifies if the result of this component call must pass by twiki render. If set to yes no autolink, substitution or any kind of formatting is performed. Sometimes it's useful, but most of times it isn't. It depends on the component. Optional. Defaults to no or %MASON_POST_RENDERING%, if defined. It can be set globally, in a web or in a topic. Web settings take precedence over global settings and topic settings take precedence over web settings.
To make it possible to MasonPlugin call the correct component it needs to know which component to call and to which application it belongs. If there is only one application available to the web/topic the
app argument can be ommited. It's also possible to set a default application, choosed when no
app is given. It's done by setting the
MASON_DEFAULT_APP variable. It can be done in a topic, web or globally (in this topic). Web settings take precedence over global settings and topic settings over web settings.
args are a list of
"key => value" pairs
- keys must begin with a letter, followed by any number of letters, digits or underscores (_).
- values can be:
- A number (integer or floating point)
- A string (and if so it needs quotes. Double quotes must be escaped with
\)
- A comma separated list of values, surrounded by
[ ].
- A list of
"key => value" pairs, surrounded by { }.
Note that these definitions are recursive, allowing to specify complex data structures if it's needed. Most of times it doesn't and things remains simple.
MasonPlugin itself doesn't require the
args specification, but some specific components of particular applications may require arguments. Refer to the application's docs for details.
-
%MASON_APPS% shows which applications are able to run, regardless permissions.
-
%MASON_ENABLED_APPS% shows which applications are enabled to run in the current web.
-
%MASON_APPS_TABLE% shows web's permissions to run applications in a table.
-
%MASON_FAILED_APPS% show error messages generated by the application's loader, if any. It's useful for initial setup of new applications.
Examples
-
%MASON_APPS% = %MASON_APPS%
-
%MASON_ENABLED_APPS% = %MASON_ENABLED_APPS%
-
%MASON_APPS_TABLE% = %MASON_APPS_TABLE%
-
%MASON_FAILED_APPS% = %MASON_FAILED_APPS%
Installing Applications
In order to an application work it needs a loader. The application loader is in charge of make any initialization process (parse configuration files, load needed modules, etc), set up some extra functionality that will be available for components and tell MasonPlugin the arguments to invoke the mason interpreter. These arguments must, at least, specify where the component's root of that application is, so the mason interpreter will be able to resolve the component path.
The directory where MasonPlugin expects application loaders is configurable via TWiki
configure script, or by editing
$TWiki::cfg{MasonPlugin}{ApplicationsDir} in
lib/TWiki.cfg or
lib/LocalLib.cfg.
For security reasons the available applications must also be specified via
configure or by setting
$TWiki::cfg{MasonPlugin}{Applications}. This field must be filled by a comma separated list of applications' name.
If
Foo and
Bar are available applications, MasonPlugin expects the loaders
Foo.pm and
Bar.pm to exist in the
ApplicationsDir. Loaders, components and specific instructions are part of applications' port. See "Porting Applications to MasonPlugin" below for details.
Be sure that:
-
ApplicationsDir is readable by the webserver user
- Component root used by applications is also readable
- Data dir used by applications is readable and writable
- The spelling of application name is right in
Applications and there exists ApplicationsDir/<AppName>.pm
- Applications are enabled for the web(s) they will be used
Use
%MASON_APPS%,
%MASON_FAILED_APPS% and
%MASON_APPS_TABLE% for diagnostics.
Security Issues
Mason components may have arbitrary Perl code, that gets executed on the server when corresponding components are called. That's why loaders directory and available applications are configured via
configure script and all applications are disabled by default.
Don't use twiki's pubdir as directory to put loaders or components. If you do so, be sure you know
exactly what you're doing. If users can upload mason components then arbitrary code
will get executed on the server.
Take a look at the loaders code and be sure that users can't upload to application's data_dir nor comp_root.
If the only choice left is to use twiki's pubdir then use
pub/_work_areas/MasonPlugin and configure webserver to deny access to this directory.
As applications get integrated to TWiki using this plugin security holes of that applications may be brought to TWiki as well. Install and make available as few applications as possible. It's also a performance tip. See bellow.
Be sure to
restrict write access to this topic. If any user can edit it then applications could be enabled globally and get you into trouble.
Warning
- The authors built and distributes this software in the hope that it will be usefull. Use it at your own risk. The authors shall not in any case be liable for special, incidental, consequential, indirect or other similar damages arising from the use of this software
Performance Tips
MasonPlugin perform its work as late as possible, and try to avoid re-executing tasks. When needed applications loaders get executed and remains in memory as long as TWiki itself. So the next time application is needed it's not necessary to load it again.
But if twiki is running as CGI script then every time a request comes (to view some topic that uses MasonPlugin) then everything is executed again, since CGI scripts don't remain in memory when the request ends. This can decrease TWiki's performance a lot, since applications can perform many tasks at initialization time. It's
very recommended to use some persistence mechanism such as
SpeedyCGI
,
FastCGI
or even
ModPerl
.
If you're porting some application to use with MasonPlugin, be in mind that loaders may be executed only once. Parse configuration files, load related modules and initialize some global data structures are good tasks to be performed by a loader.
Tasks that depends on the execution, such as user specific tasks and even database connections can be handled by autohandler mason component, within a
<%init> block.
Porting Applications to MasonPlugin
If it's possible to build a Perl application's interface using Mason, then this application can be ported to MasonPlugin. If the application already has a Mason interface then very little work is needed.
The main differences between a stand alone Mason interface and a MasonPlugin interface is that TWiki peforms most of the work, thus components with
MasonPlugin are more simple. For instance, if a component needs a table then it doesn't need to output all the table code. It can use the much cleaner twiki notation. Variables, such as
%TOPIC% are also expanded. In short, components can output twiki notation instead of html code.
But if TWiki's rendering facillities aren't desired components may output html code and user should call them with
post_render="yes".
Another important difference is that the
$r variable isn't available or doesn't have the desired effect. Sorry. If very needed components can use the CGI object, returned by
TWiki::Func::getCgiQuery().
Mason components have access to the entire
twiki plugins API, so have fun.
MasonPlugin is shipped with a module that allows to access the session as a tied hash. To use this feature use a code like this:
tie %session, 'TWiki::Plugins::MasonPlugin::SessionTieHash';
And put a
use vars qw(%session) in the loader, as in the example bellow. This way components may use
$session{key} instead of
TWiki::Func:: getSessionValue($key). The TWiki plugins API doesn't yet permit iterate trhough all session's keys, so code like
keys %session will not work.
Refer to
perltie
man page for details about the tie mechanism.
The application loader must implement the
interpArgs method, that return a hash that will be passed to mason interpreter. Here an example of a Foo loader:
# filename: Foo.pm
package Foo;
use strict;
use warnings;
sub interpArgs {
return (default_escape_flags => 'h',
comp_root => '/usr/local/share/MasonPlugin/Foo',
data_dir => '/var/lib/MasonPlugin/Foo' );
}
# Optionally bring something to HTML::Mason::Commands namespace,
# that is the namespace of components.
{
package HTML::Mason::Commands;
use vars qw(%session); # All components will be able to access the %session hash
use DBI;
use Date::Parse;
}
1; # Required!!!!
MasonPlugin gets its work done in two or three steps. In the first it discovers all component calls and applications that are needed by the topic. Then it builds a component on the fly that calls every components for an application. One component is built for each application. Theses dynamic components are executed by a Mason Interpreter, initialized with the parameters returned by
interpArgs method of the corresponding loader. In the second step all component calls that should pass through the twiki render are replaced with the corresponding result. Then, after twiki rendering, the remaining component calls are replaced.
The dynamic components inherit from
/autohandler component.
MasonPlugin makes
%masonShared available to all components belonging to some application, so they can exchange messages. Note that components order is important. If component B is executed after component A than B can't send messages to A. If your components need some special order, document this issue properly, so the users won't make a mistake.
The
%masonShared variable is good for short and fast communication. If components need some kind of persistence, such as login information, then they should use the session. Sessions can also be used to inter-application communication, since
%masonShared works with each application independently.
Many different applications and TWiki itself shares the session, so name collisions can take place. A simple way to avoid it is to prefix all keys, like in
$session{APP_key} or even
$session{APP}{key}.
Finally some guidelines to be in mind:
- Write short and well specified components
- Document components behavior and each argument it handles
- Try do write flexible components, so you give more power and freedom to users to customize their interfaces.
- Avoid performing unnecessary work
Cool Links
Plugin Settings
- One line description, is shown in the TextFormattingRules topic:
- Set SHORTDESCRIPTION = Allows to embed calls to Mason components within topics.
- Debug plugin: (See output in
data/debug.txt)
- Security Action: Uncomment the following line
By default applications are disabled for all webs. They must be enabled manually, via:
-
Set ENABLE_APPNAME_IN = comma separated web list
The special keyword
ALL enables application in all webs, public or not. Particular webs can be disabled by the web name prefixed with a minus signal. Use
ALL with care.
Even if the application's name is Foo, FoO, fOO or whathever it is, it must be written with upcase letters on permissions preferences.
Examples:
-
Set ENABLE_FOO_IN = Main, TWiki enables application Foo in Main and TWiki webs. Application name must be uppercase in permission settings.
-
Set ENABLE_BAR_IN = ALL, -Trash, -TWiki, -Main enables Bar application in all webs, except Trash, TWiki and Main.
Applications permissions must be set
only in this topic. Web and/or topic settings, if any, are discarded. See "Security Issues" above.
Plugin Installation Instructions
Note: You do not need to install anything on the browser to use this plugin. The following instructions are for the administrator who installs the plugin on the TWiki server.
- Download the ZIP file from the Plugin web (see below)
- Unzip
MasonPlugin.zip in your twiki installation directory. Content: | File: | Description: |
data/TWiki/MasonPlugin.txt | Plugin topic |
data/TWiki/MasonPlugin.txt,v | Plugin topic repository |
lib/TWiki/Plugins/MasonPlugin.pm | Plugin Perl module |
lib/TWiki/Plugins/MasonPlugin/SessionTieHash.pm | Helper Perl Module |
MasonPlugin_installer.pl | Installer script |
- Configure the Plugin:
- Run
MasonPlugin_installer.pl. It will hep you to configure ApplicationsDir and Applications
- Run the configure script to enable the Plugin
- Change the Plugin settings as needed
Plugin Info
Related Topics: TWikiPlugins,
DeveloperDocumentationCategory,
AdminDocumentationCategory,
TWikiPreferences
--
GilmarSantosJr - 26 Aug 2006