jvanzyl 01/05/12 22:04:44
Modified: xdocs/howto criteria-howto.xml python-howto.xml
sybase-howto.xml
Added: xdocs/howto security-howto.xml webmacro-site-howto.xml
Log:
- more corrections
- fixing source tags in python howto
Revision Changes Path
1.2 +3 -3 jakarta-turbine/xdocs/howto/criteria-howto.xml
Index: criteria-howto.xml
===================================================================
RCS file: /home/cvs/jakarta-turbine/xdocs/howto/criteria-howto.xml,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- criteria-howto.xml 2001/05/13 04:21:31 1.1
+++ criteria-howto.xml 2001/05/13 05:04:44 1.2
@@ -3,7 +3,7 @@
<document>
<properties>
- <title>Advanced Criteria</title>
+ <title>Criteria Howto</title>
<author email="[EMAIL PROTECTED]">Cameron Riley</author>
</properties>
@@ -12,8 +12,8 @@
<p>
For a basic description and examples of the Criteria Object with Peers please
- view the <a href="peers.html">Peers</a> and <a href="advpeers.html">Advanced
Peers</a>
- documents. This document intends to show more advanced techniques using
Criteria,
+ view the <a href="/howto/peers-howto.html">Peers Howto</a>
+ document. This document intends to show more advanced techniques using
Criteria,
such as comparators and joins. As always, for more information on the methods
available in the Criteria Object, view the javadocs.
</p>
1.2 +14 -6 jakarta-turbine/xdocs/howto/python-howto.xml
Index: python-howto.xml
===================================================================
RCS file: /home/cvs/jakarta-turbine/xdocs/howto/python-howto.xml,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- python-howto.xml 2001/05/13 04:21:31 1.1
+++ python-howto.xml 2001/05/13 05:04:44 1.2
@@ -58,14 +58,16 @@
<p>
Now we need to edit the TurbineResources.properties. Add the following
keys to your application's properties:
- <source>
+ </p>
+ <source><![CDATA[
services.AssemblerBrokerService.assembler.screen=
org.apache.turbine.util.assemblerbroker.python.PythonScreenFactory
services.AssemblerBrokerService.assembler.action=
org.apache.turbine.util.assemblerbroker.python.PythonActionFactory
services.AssemblerBrokerService.python.path=/path/to/python
- </source>
+ ]]></source>
+ <p>
The first two registers the Python Assembler Factories with the
AssemblerBrokerService. The last line tells the Python interpreter
where to find all the .py files for your application.
@@ -73,7 +75,8 @@
<p>
In the root of your services.AssemblerBrokerService.python.path
you need to add a file named config.py that looks like this:
- <source>
+ </p>
+ <source><![CDATA[
import java
from java.io import *
@@ -93,7 +96,9 @@
from org.apache.turbine.util import RunData
from org.webmacro.servlet import WebContext
from org.apache.turbine.services.security import TurbineSecurity
- </source>
+ ]]></source>
+
+ <p>
JPython sometimes gets a bit confused with the Servlet Engine
classloader, which forces us to call sys.add_package for each java
package that we wish to use in our Python code. You also need to
@@ -136,13 +141,16 @@
test.wm file (I assumer everybody knows how to do this). Now create a
test.py and place it in the python-path/screens directory. It should
look something like this:
- <source>
+ </p>
+ <source><![CDATA[
+
class Subjectslist(WebMacroSiteScreen):
def doBuildTemplate (self,data):
context = self.getContext(data)
context.put ("me","Leon")
context.put ("text","Python is cool");
- </source>
+ ]]></source>
+ <p>
For more information about the self parameter see the Python docs. You
can call any java code that you would normally be able to use (just
remember to add it to conf.py) including database, services, etc. You
1.2 +1 -1 jakarta-turbine/xdocs/howto/sybase-howto.xml
Index: sybase-howto.xml
===================================================================
RCS file: /home/cvs/jakarta-turbine/xdocs/howto/sybase-howto.xml,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- sybase-howto.xml 2001/05/13 04:21:31 1.1
+++ sybase-howto.xml 2001/05/13 05:04:44 1.2
@@ -32,7 +32,7 @@
<LI>Generate your application with the TDK as normal.</LI>
<LI>Edit the project properties as instructed by the TDK.</LI>
<LI>
-Before you run 'build-project.sh init' you will need to create the
+Before you run 'build.sh init' you will need to create the
database. Automatic database creation for Sybase does not currently
work, so the database must be created first.
</LI>
1.1 jakarta-turbine/xdocs/howto/security-howto.xml
Index: security-howto.xml
===================================================================
<?xml version="1.0"?>
<document>
<properties>
<title>Turbine Services</title>
<author email="[EMAIL PROTECTED]">Cameron Riley</author>
</properties>
<body>
<section name="Turbine Security">
<p>
The Turbine Security includes a <a href="services/security-service.html">Security
Service</a>
as well as Actions and Screens that can be extended in the Templating Services.
</p>
</section>
<!-- Start -->
<section name="Users, Groups, Roles and Permissions">
<p>
The default Relational Database schema that Turbine uses for the database security
service, and which the TDK is generated with upon initialisation, includes the
data structure for the managing of permissions.
The default or core schema can be viewed at;
</p>
<p>
<ul><a href="turbine-schema.html">Turbine Core Schema</a></ul>
</p>
<p>
The main tables are TURBINE_GROUP, TURBINE_USER, TURBINE_ROLE and
TURBINE_PERMISSION.
The Permissions are the individual actions a user is allowed to take in the system.
The Role is a container for the Permissions, in other words a Role can be made of
many Permissions. User is an account that is interaction with the System and the
Group
is a something that a User would want to do something in. In the Turbine mailing
lists
it has often been described in the same way as a project. In a project you have
fulfill
a role, however a User doesnt "belong" to a project they merely have a role in that
project ( or group ). In this manner too a User can have many Roles within the one
Group. For instance a User may have the Role Developer in the Group, but may also
have
the Role of Administrator as well. While initially confusing at first, as there
are no group-user or role-user containers, it is a flexible system and strong system.
</p>
</section>
<section name="Access Control Lists">
<p>
A User's interaction through the system is controlled by the Permissions they are
able to partake in. The AccessControlLists manage this information and present it
via
RunData and User Interfaces to the application. The RunData interface through the
getACL() method presents the AccessControlList Object.
</p>
<source>
//get the AccessControlList Object
//from RunData
AccessControlList acl = data.getACL();
//check if the User ( from the http request )
//has permission to view the invoices
if( acl.hasPermission("viewinvoice") )
{
data.setMessage("You have permission to view the invoices.");
setTemplate(data, "Invoice.vm");
}
else
{
data.setMessage("You do not have Permission to view the Invoices");
setTemplate(data, "UnauthorizedRequest.vm");
}
</source>
<p>
This will check if the User has permission to view this in the Global Group which
is useful for managing Anonymous Users as well as logged in Users across your
application. If however you need stronger security, such as only allowing users that
have logged in, and have a Role in a specific Group, the Permission will need to be
matched to the Group and User. As an example, assume one of your groups is
"Accounting"
and the Invoice information is only to be viewed by Usersthat have a Role in
Accounting
as well as the Permission "viewinvoice", the above method would be re-written;
</p>
<source><![CDATA[
//get the User from RunData
User user = data.getUser();
//get the AccessControlList Object
//from RunData
AccessControlList acl = data.getACL();
//check if the User has logged in,
//has a role in the group and
//has permission to view the invoices
if( user.hasLoggedIn() &&
acl.hasPermission("viewinvoice", "Accounting") )
{
data.setMessage("You have permission to view the invoices.");
setTemplate(data, "Invoice.vm");
}
else
{
data.setMessage("You do not have Permission to view the Invoices");
setTemplate(data, "UnauthorizedRequest.vm");
}
]]></source>
<p>
If instead the Permission could be across any of the Roles the User has, the
method acl.hasPermission(String permission, GroupSet groups), can be used. As
always check the Javadocs for more detail.
</p>
</section>
<section name="Templates and Logging In">
<p>
Managing Anonymous Users and Logged In Users poses problems in applications for
managing
the Secure/Strong parts of the application and the Unsecure/Weak parts of the
application. In Turbine, the Action and Screen components make managing this process
quite simple. Assume the only Velocity Template allowed to be viewed without being
logged in is the actual Login.vm template. As this is the only Screen that
needs to be Unsecure/Weak we can manage this via the parent of Login Screen.
</p>
<source>
package com.mycompany.modules.screens;
//parent which allows Users to view the screen
public class WeakScreen extends VelocityScreen
{
//nothing to check that the User
//can view this screen
protected void doBuildTemplate( RunData data, Context context )
throws Exception
{
//call to Super
super.doBuildTemplate(data, context);
}
}
package com.mycompany.modules.screens;
//the java component of the Login Velocity Template
public class Login extends WeakScreen
{
//nothing to check that the User
//can view this screen
protected void doBuildTemplate( RunData data, Context context )
throws Exception
{
context.put("date",new Date());
//call to Super
super.doBuildTemplate(data, context);
}
}
</source>
<p>
Note that there is nothing in that method which checks that the User has logged in.
On the other hand, for the Secure or Strong Actions and Screens we would want a
check to ensure that the User has logged in.
</p>
<source>
package com.mycompany.modules.screens;
//Strong screen which checks for login
public class StrongScreen extends VelocityScreen
{
//check that User has Logged in before bothering
//to add anything to the context.
protected void doBuildTemplate( RunData data )
throws Exception
{
if (data.getUser().hasLoggedIn())
{
doBuildTemplate( data, TurbineVelocity.getContext( data ) );
}
else
{
//send the User to the Login Template
data.setMessage("Please Login first!");
setTemplate(data,"Login.vm");
}
}
}
package com.mycompany.modules.screens;
//as an example use the Invoices again
public class Invoice extends StrongScreen
{
//can view this screen
protected void doBuildTemplate( RunData data, Context context )
throws Exception
{
context.put("invoice",new Invoice());
//call to Super
super.doBuildTemplate(data, context);
}
}
</source>
<p>
In the latter example, before the Screen populates the Context it will check for the
User being logged in by the doBuildTemplate(data) method in the parent. If the test
fails, the context isnt created for the Invoice screen. Another way to manage this
is to seperate the screens into two packages, com.mycompany.modules.screens.unsecure
and com.mycompany.modules.screens.secure and have a Default.java Screen in each
of the packages mimicing the above approaches.
</p>
</section>
</body>
</document>
1.1 jakarta-turbine/xdocs/howto/webmacro-site-howto.xml
Index: webmacro-site-howto.xml
===================================================================
<?xml version="1.0"?>
<document>
<properties>
<title>WebMacro Site</title>
<author email="[EMAIL PROTECTED]">Turbine Documentation Team</author>
</properties>
<body>
<section name="WebMacro Site">
<p>
In Turbine, we have excellent integration with the template tool
<a href="http://www.webmacro.org/">WebMacro</a>,
we call this WebMacroSite building. The reason why we want to wrap Turbine
around WebMacro instead of using it on its own is to provide a completely
MVC model for building web applications where the framework has control
over the authentication, security, connection pool, etc and WebMacro is
simply used as the View portion of the MVC model. Turbine is responsible
for helping you manage all the different templates as well so that you
can easily construct a site that both designers and engineers can work
together on (<strong>that is our primary goal!</strong>). The reason why this is
good is that it will help you design and build web applications that have
more functionality and less duplication of code since Turbine is fully
re-usable.
</p>
<p>
Knowledge of how WebMacro works and what a WebMacro Context object is
are required for understanding this documentation. This documentation also
assumes that you are using a Servlet API 2.2 and higher serlvet engine
such as <a href="http://jakarta.apache.org/tomcat/">Tomcat</a> because
we are now targeting towards using WAR archives. Although, this should
work with older servlet engines as well...it just may be slightly harder
for you to setup. You should also be familiar with the rest of the Turbine
documentation that is referenced on the <a href="index.html">index page</a>.
</p>
<p>
Here is a brief description of the way that the system works: all requests
are passed through the Turbine Servlet. The servlet is then responsible
for brokering the request, building up the Context object and then calling
WebMacro's template engine to process your template document and return
the results. Pretty simple. Now, lets move on to some more detailed
instructions...:-)
</p>
</section>
<section name="Screens">
<p>
Lets start off with a simple WebMacro Screen to get things rolling
so you can see how powerful things are. You should compile this class into
your <em>WEB-INF/classes</em> directory.
</p>
<source><![CDATA[
// WebMacro Stuff
import org.webmacro.*;
import org.webmacro.servlet.*;
import org.webmacro.util.*;
// Turbine Stuff
import org.apache.turbine.util.RunData;
import org.apache.turbine.modules.screens.WebMacroSiteScreen;
public class HelloWorld extends WebMacroSiteScreen
{
public void doBuildTemplate( RunData data, Context context )
throws Exception
{
// the context object has already been setup for you!
context.put ("hello", "this is a test...");
}
}
]]></source>
<p>
Ok, as you can see, you do not even need to return a value from your method!
You simply stuff objects into the WebMacro Context and that is it! Next,
you will want to create a .wm template of the same name as your class:
HelloWorld.wm...within that template you will put the BODY portion of your
page. In other words, there is no reason to put the header/footer into
this file since that will be built seperately (more documentation on that
futher down...). You should save this document in your <em>templates/screens/</em>
directory.
</p>
<source><![CDATA[
<p>
<font color="red">
$hello of the emergency broadcast station.
<font>
</p>
]]></source>
<p>
When you request a URL like this:
</p>
<p>
http://www.server.com/servlet/Turbine/template/HelloWorld.wm
</p>
<p>
What that will do is cause the system to first execute the HelloWold.java
class (if it exists) and then it will call WebMacro's template engine directly
and execute the HelloWorld.wm template and then return the results back
to you.
</p>
<p>
<em>NOTE:</em> Turbine capitalizes the first letter in the class file name
before looking for the matching class in the classpath. This allows you to
follow (somewhat) normal class naming guidelines. For example:
</p>
<p>
index.wm and Index.wm both map to Index.class
roleeditor.wm maps to Roleeditor.class
role_editor.wm maps to Role_editor.class
</p>
<p>
The result will be a fully formed HTML document with the <em>$hello</em>
replaced with the value: "this is a test...". If you want to make the URI
above shorter or easier to read, you could simply re-write things using
<a href="http://www.apache.org/docs/mod/mod_rewrite.html">mod_rewrite</a>.
For example, by removing the "<em>/servlet/Turbine/template</em>" portion
of the URI.
</p>
<p>
As you can see, this is much easier than doing servlet after servlet
because it removes a lot of the setup and other things that could potentially
go wrong. It also makes the individual template files easier to manage
and more re-usable because there isn't any surrounding page layout mixed
in with the page.
</p>
<p>
If you want to do something that is more complicated than this that
is reflected across all of your Screens, then you should write a class
that is a subclass of WebMacroSiteScreen and then put your specific code
in there. For example, if you wanted a security method to be called automaticially
without having to normally call super() to get it from an overridden method
in the superclass, you could have something like this (semi-pseudo untested
code):
</p>
<source><![CDATA[
// WebMacro Stuff
import org.apache.webmacro.Context;
// Turbine Stuff
import org.apache.turbine.util.RunData;
import org.apache.turbine.modules.screens.WebMacroSiteScreen;
public abstract class SecureScreen extends WebMacroSiteScreen
{
protected boolean doCheckSecurity(RunData data)
throws Exception
{
if (data.isSecure())
return true;
else
return false;
}
/*
* override the doBuild() method of the
* TemplateScreen to always check security first
*/
public void doBuild(RunData data, Context context) throws Exception
{
if ( !this.doCheckSecurity(data))
{
// set the template and screen to be different or do
// some other short circuit code here
}
doBuildTemplate(data, context);
return super.buildTemplate(data, context);
}
}
]]></source>
<p>
What this would do is override the doBuild() method in TemplateScreen (which
is the base class that WebMacroSiteScreen subclasses from) and have it
always do a security check before displaying the content. The benefit of
this is that all you need to do to add security to your screen is to simply
subclass this class instead of WebMacroSiteScreen. There is also no need
to remember to call super() since the doBuild() method will be called for
you automaticially by Turbine. You can start to see how Turbine is simply
an extension of the servlet framework itself. For example, the Servlet
Engine will call HttpServlet's service() method for you, just like Turbine
will call your doBuild() method for you. Tight integration with tools like
WebMacro just make things even cleaner. :-)
</p>
<p>
One other feature in this system is that if you are not building up
a Context object that is specific for your screen, then you do not need
to create a Java class to match the template file. You simply create the
.wm template and put it in a directory and call it with the same URI described
above. This is really useful when you have a static site of content that
you are converting to be dynamic and you only want to do small portions
of it at any one time. You can also do the opposite of this which is to
only create a Java class file and no template file. You can do this by
simply overriding the doBuild() method in TemplateScreen and returning
your results directly instead of attempting to build a template. Later,
when you want to add a template and remove the HTML code, you can change
the doBuild() into a doBuildTemplate(), build the Context object up and
you are done. Cool!
</p>
<p>
Here is an example of having templates in subdirectories and making
links to each of them...
</p>
<p>
Create a directory structure like this:
</p>
<p>
WEB-INF/templates/screens/admin/
Put <em>index.wm</em> into the <em>screens/</em> directory.
Put <em>UserAdmin.wm</em> into the <em>screens/admin/</em> directory.
</p>
<p>
In index.wm, if you want to link to UserAdmin.wm, you would add something
like this to the HTML:
</p>
<source><![CDATA[
<a href="$link.setPage("admin,UserAdmin.wm")</font>">User Admin Screen</a>
]]></source>
<p>
As you can see above, I used a "," instead of a "/". You can use either
one here. The above will create a fully formed URI with the session information
encoded into the link if the clients brower has cookies turned off.
</p>
</section>
<section name="Layout and Navigations">
<p>
Now that you know how to create simple Screens, you are probably wondering
where the layout and navigation portions of the page come from and how
you control that. If you were not wondering that, then shame on you. :-)
Essentially, it is the same exact procedure as before except you subclass
WebMacroSiteLayout and WebMacroSiteNavigation instead. Again, it is possible
to not have Java class files always match up with the template and in most
cases, you probably won't need to have a user defined Context in the Layout.
</p>
<p>
Below is an example Layout. It will be searched for in the templates/layouts
directory structure and also takes advantage of the same template path
lookup code as described below:
</p>
<source><![CDATA[
#if ( $data.getMessage() )</font>
{
$data.getMessage()
}
<table width="100%">
<tr>
<td>$navigation.setTemplate("/default_top.wm")</td>
</tr>
<tr>
<td>$screen_placeholder</td>
</tr>
<tr>
<td>$navigation.setTemplate("/default_bottom.wm")</td>
</tr>
</table>
]]></source>
<p>
The variable <em>$screen_placeholder</em> is important here because that
is where the output from your Screen will be placed. WebMacroSiteLayout
is responsible for taking care of this. The other variables are for including
your Navigations into the system. The benefit of all of this is that it
enforces the View portion of the MVC model because the "body" and "navigation"
portions of your page simply becomes a variable that you can plug into
any number of Layouts and in any location. If you want to write code so
that the Layout is determined by a variable in the database or in the HTTP
request or whever, all you need to do is write your own WebMacroSiteLayout
and override some of the methods in there to determine the layout based
on your own conditions instead of the system default conditions.
</p>
</section>
<section name="How the templates are found">
<p>
Since everything is keyed off the template variable, if
<em>data.getParameters().getString("template")</em>
returns <em>/about_us/directions/driving.wm</em>, the search for the Screen
class is as follows (in order):
<ol>
<li>
about_us.directions.Driving</li>
<li>
about_us.directions.Default</li>
<li>
about_us.Default</li>
<li>
Default</li>
<li>
WebMacroSiteScreen</li>
</ol>
</p>
<p>
If the template variable does not exist, then <em>WebMacroSiteScreen</em>
will be executed and <em>templates/screens/index.wm</em> will be executed.
If <em>index.wm</em> is not found or if the template is invalid or WebMacro
execution throws an exception of any reason, then <em>templates/screens/error.wm</em>
will be executed.
</p>
<p>
For the Layouts and Navigations, the following paths will be searched
in the layouts and navigations template subdirectories (in order):
</p>
<p>
<ol>
<li>
/about_us/directions/driving.wm</li>
<li>
/about_us/directions/default.wm</li>
<li>
/about_us/default.wm</li>
<li>
/default.wm</li>
</ol>
</p>
</section>
<section name="Actions">
<p>
Actions happen when you have an <em>action</em> parameter defined in the
URI. For example:
</p>
<p>
<u>http://www.server.com/servlet/Turbine/template/HelloWorld/action/UpdateWorld</u>
In this case, what happens is that the class UpdateWorld class (located
in your <em>WEB-INF/classes/PACKAGE/actions/</em> directory) is executed
first before anything. Then your HelloWorld class (located in your
WEB-INF/classes/PACKAGE/screens/
directory) is executed. Then your template (for screen/navigation/layout)
HelloWorld.wm is executed. The point of an action is that it should perform
some sort of "action" on your system. Usually, this means storing some
information from a POST request into a database or sending email or something
of that nature. Actions themselves do not return results, but may set a
message with data.setMessage(). They can also short circuit the system
by changing the Template and Screen to be executed. You might want to do
that if there is an error with the form data and you want to re-display
the same page again. Unlike most of the rest of the modules (ie: Screens,
Navigations, Layouts), there is no corresponding WebMacro template file
for an Action.
</p>
<source><![CDATA[
// WebMacro Stuff
import org.apache.webmacro.Context;
// Turbine Stuff
import org.apache.turbine.util.RunData;
import org.apache.turbine.modules.actions.WebMacroAction;
public class AddUser extends WebMacroAction
{
public void doPerform( RunData data, Context context ) throws Exception
{
if ( data.getParameter.getString("username",null) == null)
{
data.setMessage("Username does not exist");
setTemplate ( data, "AddUser.wm" );
return;
}
// store user info into database
data.setMessage("Information stored!");
setTemplate( data, "MainMenu.wm");
// stuff something into the WebMacro Context
context.put ("variable", "foo");
}
}
]]></source>
<p>
In the very basic example Action above, a check is performed to make sure
that
the form data contained a "username" variable. If there is no data, the
template is changed back to the "AddUser" template and the processing is
stopped with an error message that can be easily displayed in the template.
If the processing finishes, then the MainMenu.wm template will be shown
and the message can be displayed.
</p>
</section>
<section name="Action Event">
<p>
There is also a new feature of Turbine that the WebMacroSiteAction takes
advantage of, it is called <a href="action-event.html">Action Event</a>.
Please click the link and read more documentation about it. This is an
excellent way to write your actions because now they are entirely event
driven based on which button was clicked in the HTML form.
</p>
</section>
</body>
</document>
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]