| <?xml version="1.0"?> |
| |
| <document> |
| <properties> |
| <title>Velocity Site Howto</title> |
| <author email="jvanzyl@apache.org">Turbine Documentation Team</author> |
| </properties> |
| |
| <body> |
| |
| <section name="Velocity Site"> |
| |
| <p> |
| In Turbine, we have excellent integration with the template tool |
| <a href="http://jakarta.apache.org/velocity/">Velocity</a>, |
| we call this VelocitySite building. The reason why we want to wrap Turbine |
| around Velocity 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 Velocity 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 Velocity works and what a Velocity 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 |
| Velocity'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 Velocity 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> |
| |
| <p> |
| Note: In the examples below, you should replace <code>com.yourcompany.app</code> |
| with the correct value for your application. |
| </p> |
| |
| <source> |
| package com.yourcompany.app.modules.screens; |
| |
| // Velocity Stuff |
| import org.apache.velocity.context.Context; |
| |
| // Turbine Stuff |
| import org.apache.turbine.util.RunData; |
| import org.apache.turbine.modules.screens.VelocityScreen; |
| |
| public class HelloWorld extends VelocityScreen |
| { |
| 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 Velocity Context and that is it! Next, |
| you will want to create a .vm template of the same name as your class: |
| HelloWorld.vm...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> |
| |
| <p> |
| You will also need to modify your TurbineResources.properties file to tell |
| Turbine where to look for your new screen class. |
| </p> |
| |
| <source> |
| module.packages=org.apache.turbine.modules, com.yourcompany.app.modules |
| </source> |
| |
| <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.vm |
| </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 Velocity's template engine directly |
| and execute the HelloWorld.vm 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.vm and Index.vm both map to Index.class |
| |
| roleeditor.vm maps to Roleeditor.class |
| |
| role_editor.vm 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 VelocityScreen 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> |
| package com.yourcompany.app.modules.screens; |
| |
| // Velocity Stuff |
| import org.apache.velocity.context.Context; |
| |
| // Turbine Stuff |
| import org.apache.turbine.util.RunData; |
| import org.apache.turbine.modules.screens.VelocityScreen; |
| |
| public abstract class SecureScreen extends VelocityScreen |
| { |
| 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 VelocityScreen 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 VelocityScreen. 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 |
| Velocity 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 |
| .vm 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.vm</em> into the <em>screens/</em> directory. |
| Put <em>UserAdmin.vm</em> into the <em>screens/admin/</em> directory. |
| </p> |
| |
| <p> |
| In index.vm, if you want to link to UserAdmin.vm, you would add something |
| like this to the HTML: |
| </p> |
| |
| <source><![CDATA[ |
| <a href="$link.setPage("admin,UserAdmin.vm")">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 |
| VelocitySiteLayout and VelocitySiteNavigation 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() ) |
| { |
| $data.getMessage() |
| } |
| |
| <table width="100%"> |
| |
| <tr> |
| <td>$navigation.setTemplate("/default_top.vm")</td> |
| </tr> |
| <tr> |
| <td>$screen_placeholder</td> |
| </tr> |
| <tr> |
| <td>$navigation.setTemplate("/default_bottom.vm")</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. VelocitySiteLayout |
| 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 VelocitySiteLayout |
| 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.vm</em>, the search for the Screen |
| class is as follows (in order): |
| </p> |
| |
| <ol> |
| <li>about_us.directions.Driving</li> |
| |
| <li>about_us.directions.Default</li> |
| |
| <li>about_us.Default</li> |
| |
| <li>Default</li> |
| |
| <li>VelocityScreen</li> |
| </ol> |
| |
| <p> |
| If the template variable does not exist, then <em>VelocityScreen</em> |
| will be executed and <em>templates/screens/index.vm</em> will be executed. |
| If <em>index.vm</em> is not found or if the template is invalid or Velocity |
| execution throws an exception of any reason, then <em>templates/screens/error.vm</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> |
| |
| <ol> |
| <li>/about_us/directions/driving.vm</li> |
| |
| <li>/about_us/directions/default.vm</li> |
| |
| <li>/about_us/default.vm</li> |
| |
| <li>/default.vm</li> |
| </ol> |
| |
| </section> |
| |
| <section name="Actions"> |
| |
| <p> |
| Actions happen when you have an <em>action</em> parameter defined in the |
| URI. For example: |
| </p> |
| |
| <p> |
| <ul><u>http://www.server.com/servlet/Turbine/template/HelloWorld.vm/action/UpdateWorld</u></ul> |
| </p> |
| |
| <p>In this case, what happens is that the class UpdateWorld class (located in your |
| <em>WEB-INF/classes/com/yourcompany/app/modules/actions/</em> directory) |
| is executed first before |
| anything. Then your HelloWorld class (located in your |
| WEB-INF/classes/com/yourcompany/app/modules/screens/ |
| directory) is executed. Then your template (for screen/navigation/layout) |
| HelloWorld.vm 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 Velocity template file |
| for an Action. |
| </p> |
| |
| <source> |
| package com.yourcompany.app.modules.actions; |
| |
| // Velocity Stuff |
| import org.apache.velocity.context.Context; |
| |
| // Turbine Stuff |
| import org.apache.turbine.util.RunData; |
| import org.apache.turbine.modules.actions.VelocityAction; |
| |
| public class AddUser extends VelocityAction |
| { |
| public void doPerform( RunData data, Context context ) throws Exception |
| { |
| if ( data.getParameters().getString("username",null) == null) |
| { |
| data.setMessage("Username does not exist"); |
| setTemplate ( data, "AddUser.vm" ); |
| return; |
| } |
| |
| // store user info into database |
| data.setMessage("Information stored!"); |
| setTemplate( data, "MainMenu.vm"); |
| |
| // stuff something into the Velocity 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.vm 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 VelocitySiteAction takes |
| advantage of, it is called <a href="action-event-howto.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> |
| |
| <section name="Velocity Frames"> |
| |
| <p> |
| Frames are easily achieved with Velocity, the frameset tag being implemented at |
| the screen level. The default setting for the layout.default directive in the |
| TurbineResources.properties is the VelocityECSLayout class. |
| The VelocityECSLayout wraps the Screen in Body tags. For frames this needs to be |
| removed. The layout.default needs to be changed to; |
| </p> |
| |
| <source> |
| layout.default=VelocityOnlyLayout |
| </source> |
| |
| <p> |
| The layout Velocity template needs to point to the screen_placeholder. As an |
| example modify the Default.vm in the /WEB-INF/templates/layouts/; |
| </p> |
| |
| <source> |
| $screen_placeholder |
| </source> |
| |
| <p> |
| The screen_placeholder marker will load and process the template marked as the |
| template.homepage in the TurbineResources.properties. To create frames this is |
| the template which will need to contain the frameset tag. Edit |
| /WEB-INF/templates/screens/Index.vm; |
| </p> |
| |
| <source><![CDATA[ |
| $page.setTitle("Frames example"); |
| |
| <frameset> |
| <frame src="$link.getPage("FrameTop.vm")" /> |
| <frame src="http://www.something.com/" /> |
| </frameset> |
| ]]></source> |
| |
| <p> |
| Create a FrameTop.vm template in the /WEB-INF/templates/screens directory. The |
| top frame will load this template. The reference to something.com requires an |
| internet connection and is shown as an example, anything can be linked to the |
| lower frame, another Velocity Screen for instance. |
| </p> |
| |
| <source><![CDATA[ |
| ## Example FrameTop.vm |
| <p><b>The FrameTop Velocity Template</b> |
| ]]></source> |
| |
| </section> |
| |
| <section name="Multiple Velocity Paths"> |
| |
| <p> |
| The VelocityService can support many paths for the Velocity Templates to |
| be loaded and read from. This is specified in the |
| TurbineResources.properties file; |
| </p> |
| |
| <source> |
| services.VelocityService.file.resource.loader.path = /templates,/my-templates,/more-tempates |
| </source> |
| |
| <p> |
| The multiple paths are comma delimited and are specified from the |
| Servlet Engines context. |
| </p> |
| |
| </section> |
| |
| </body> |
| </document> |
| |