JavaDoc
Here are the API JavaDoc.
Requirements
JDK 1.5 and a J2EE 1.4 compliant servlet container.
Bluprint configuration files
In order to configure Bluprints there are two types of configuration files. The first is the bluprints.properties which used only used if you are leveraging the org.sf.bluprints.EngineManager class. This class uses this file to locate the Bluprint XML files as well as the reload interval.
This properties file has two properties and looks like this:
bluprints.configuration.uris=/one.xml, /two.xml, /three.xml,/four.xml bluprints.reload.seconds=36000
The bluprints.configuration.uris property is a comma separated list (that is trimmed when split) that points to classpath URIs of Bluprint configuration files. The bluprints.reload.seconds property is an integer value that contains the interval in seconds between reloads of all of the configuration files.
The second type of configuration files are the XML configuration files that define the Bluprints themselves. These files are described in the next section.
Bluprint XML definition
Bluprints are defined in XML configuration files. By default a file named bluprints.xml is loaded from the root of the classpath. You can specify any number of configuration files using the bluprints.properties file or by custom coding to the org.sf.bluprints.Engine class.
XML Schema URLs
The schemas for the XML definition files are always kept up-to-date on the bluprints website and are all located at this URL http://bluprints.sourceforge.net/schemas. Under this directory there is a directory for each release and in that directory a single file named bluprints.xml. Therefore, the URL for the 0.4 release is http://bluprints.sourceforge.net/schemas/0.4/bluprints.xsd.
Configuration file structure
A Bluprint XML definition with the schema included looks like this:
<bluprints xmlns="http://bluprints.sourceforge.net/schemas/0.4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://bluprints.sourceforge.net/schemas/0.4 http://bluprints.sourceforge.net/schemas/0.4/bluprints.xsd"> <bluprint name="page1" uri="page.jsp"> <parameter name="title" value="My Page1"/> <content> <bluprint name="footer" uri="footer.jsp"/> </content> </bluprint> </bluprints>
At the top level there must be a root element named bluprints. This element can only contain elements named bluprint, which each define a Bluprint definition. We understand that the s / no s is a anti-pattern, but just couldn't subject our users to long XML names. And we have a schema, which should make everyone who uses an IDE's life easier.
Namespaces
A Bluprint configuration file may assign a namespace to itself using the namespace attribute on the bluprints element like this:
<bluprints namespace="foo"> </bluprints>
If a namespace is defined all of the TOP LEVEL bluprints in that configuration file will exist in that namespace. They can only be accessed using a namespace qualified name. Here is an example configuration file:
<bluprints namespace="home"> <bluprint name="page1" uri="page.jsp"> <parameter name="title" value="My Page1"/> <content> <bluprint name="footer" uri="footer.jsp"/> </content> </bluprint> </bluprints>
The page1 page can only be accessed in these ways:
// Option #1 Engine eng = new Engine("/bluprints.xml"); Bluprint bp = eng.getPage("home:page1"); // Option #2 Bluprint bp = EngineManager.getEngine().getPage("home:page1"); // Option #3 in xwork.xml <result type="bluprint">home:page1</result> // Option #4 by hand ConfigurationParser parser = new ConfigurationParser(); Map<String, BluprintsNamespace> map = parser.build("/bluprints.xml"); BluprintsNamespace bn = map.get("home"); Bluprint bp = bn.getPage("page1"); // This can be easily expanded to a servlet/struts/verge/grails/whatever. We did WebWork in // 7 lines of code and will eventually do more, but if you write one, just submit it back!
The reason only top level elements are namespaced is that it allows for nested elements to be used without worrying about which namespace they might have been inherited from. This makes extension really simple.
When no namespace is defined the namespace defaults to default. This namespace has special handling. If you use the code above and just remove the home: portion you end up asking for Bluprints in the default namespace. This allows for easy handling of small configurations and smaller applications. Here is an example configuration file:
<bluprints> <bluprint name="page1" uri="page.jsp"> <parameter name="title" value="My Page1"/> <content> <bluprint name="footer" uri="footer.jsp"/> </content> </bluprint> </bluprints>
Using the default namespace, page1 can be accessed like this:
// Option #1 Engine eng = new Engine("/bluprints.xml"); Bluprint bp = eng.getPage("page1"); // Option #2 Bluprint bp = EngineManager.getEngine().getPage("page1"); // Option #3 in xwork.xml <result type="bluprint">page1</result> // Option #4 by hand ConfigurationParser parser = new ConfigurationParser(); Map<String, BluprintsNamespace> map = parser.build("/bluprints.xml"); BluprintsNamespace bn = map.get("default"); Bluprint bp = bn.getPage("page1"); // This can be easily expanded to a servlet/struts/verge/grails/whatever. We did WebWork in // 7 lines of code and will eventually do more, but if you write one, just submit it back!
A single Bluprint definition
Each Bluprint definition must have a name and either an extends or uri attribute but not both. The name is a descriptive name that can be used when other Bluprint's extend a Bluprint. The uri attribute should reference the JSP or other URI that will be rendered by the Web container. Normally this is a JSP, but could be any valid URI.
Parameters
Within a Bluprint definition any number of parameters can be defined. Parameters are simple name value pairs and no replacement on them is currently done although this might be a nice feature to add if someone wants to work on it. I would suggest using the Java.net Commons VariableExpander or Ognl. Although Ognl has a LOT of dependencies and that would really suck. Java.net Commons has no dependencies so that might be a lot better.
Extension
If a Bluprint provides an extension definition it must reference another TOP LEVEL Bluprint definition. This is done because nested extensions just gets ugly, messy and dangerous since nested bluprints can have the same name as top level bluprints. Here's an example where the nested element has the same name as a top level:
<bluprints> <bluprint name="footer" uri="footer.jsp"> <content> <bluprint name="bottom-nav" uri="bottom-nav.jsp"/> </content> </bluprint> <bluprint name="homepage" uri="homepage.jsp"> <parameter name="title" value="My Homepage"/> <content> <bluprint name="footer" uri="homepage-footer.jsp"/> </content> </bluprint> </bluprints>
Here is an example of a simple extension:
<bluprints> <bluprint name="layout" uri="layout.jsp"> <parameter name="number" value="1-800-555-1234"/> <content> <bluprint name="bottom-nav" uri="bottom-nav.jsp"/> </content> </bluprint> <bluprint name="homepage" extends="layout"> <parameter name="title" value="My Homepage"/> <content> <bluprint name="body" uri="homepage.jsp"/> </content> </bluprint> </bluprints>
A Bluprint can extend any top level Bluprint in any namespace. When an element is extended all of its parameters and content are available in the sub-Bluprint. Using the example above, the Bluprint named homepage has two parameters, number and title. It also has two content elements, bottom-nav and body.
Extension can also be used to override and change parameters and content. If a parameter exists in the parent Bluprint and the child Bluprint than the child value wins. The same is true for content. Here is an example of overridding:
<bluprints> <bluprint name="layout" uri="layout.jsp"> <parameter name="number" value="1-800-555-1234"/> <parameter name="title" value="Standard"/> <content> <bluprint name="top-nav" uri="top-nav.jsp"/> <bluprint name="bottom-nav" uri="bottom-nav.jsp"/> </content> </bluprint> <bluprint name="homepage" extends="layout"> <parameter name="title" value="My Homepage"/> <content> <bluprint name="body" uri="homepage.jsp"/> <bluprint name="bottom-nav" uri="homepage-bottom-nav.jsp"/> </content> </bluprint> </bluprints>
Here the Bluprint named homepage has overridden the Bluprint named layout's parameters and content. The only parameter that is inherited is named number and the only content that is inherited is named top-nav.
NOTE At some point in the extension chain, a Bluprint must define a URI, otherwise a runtime exception will be thrown.
Bluprint nesting
As has already been illustrated Bluprints can be nested as deep as needed. Nested Bluprints do not use namespaces but can have extend any TOP LEVEL Bluprints and can have any levels of nesting themselves. They behave exactly as the TOP LEVEL Bluprints do. Here is an example of a nesting:
<bluprint name="page1" extends="pageTemplate"> <parameter name="title" value="My Page1"/> <content> <bluprint name="footer" uri="myFooter.jsp"/> <content> <bluprint name="search" uri="search.jsp"> <parameter name="search" value="Enter Search"/> <content> <bluprint name="searchForm" uri="searchForm.jsp"/> </content> </bluprint> </content> </bluprint> </content> </bluprint>
Any Bluprint defined regardless of the nesting depth can define as many parameters and content Bluprints as needed.
The container of a Bluprint is defined as the Bluprint whose content contains the current Bluprint. In the example above, the container of Bluprint named searchForm is the Bluprint named search whose container is the Bluprint named footer.
If a Bluprint is nested, all of the parameters from its container are available to the Bluprint. In the example above the Bluprint named searchForm has available the parameters named search and title. This happens because of the recursive nature of Bluprints.
Parameter visibility
One of the most complex parts of Bluprints is the idea of parameter visibility. When parameters are collected and placed into the Map inside a Bluprint definition, they are placed there in a very specific order so that parameters are overridden correcly. This order is as follows:
- Add all of the current Bluprint's container's parameters (only applicable for nested Bluprints)
- Add all of the current Bluprint's parent's parameters (the parent is defined as the Bluprint which is being extended. See the extension section for more info) (only applicable for Bluprints which extend other Bluprints)
- Add the current Bluprint's parameters
Definition reloading
Bluprints can be reloaded at certain intervals using the bluprints.properties configuration file as described above.
WebWork integration
In order to use Bluprints with WebWork you need to define an additional result type in the webwork XML configuration file or in the xwork configuration file. Here is how that is defined inside the xwork configuration file:
<package name="default" extends="webwork-default"> <result-types> <result-type name="bluprint" class="org.sf.bluprints.WebWorkViewResolver"/> </result-types> <action name="test"> <result name="success" type="bluprint">home</result> </action> ... </package>
You might be better off copying the webwork-default.xml file from the WebWork JAR and adding in the new result type and then including this file in the xwork configuration file.
JSP tag library
Using Bluprints is simple with WebWork, but can be extended to allow for any framework integration or a servlet based solution. The WebWork integration places the current Bluprint definition into the request scope under the name bluprint. This can then be accessed on the JSP. Here is an example of accessing Bluprint parameters from the JSP.
<title>${bluprints.parameters.title}</title>
Including nested content on a JSP is also simple. This is done by including the Bluprints tag library at the top of the page like this:
<%@ taglib prefix="bluprint" uri="http://bluprints.sourceforge.net" %>
Then on the JSP you can include a content element of the current Bluprint like this:
<bluprint:include content="header" flush="true" ignore="true"/>
This will include the header Bluprint, which must be defined in the content block of the current Bluprint. When a page is included, the parameter in the request named bluprint is replaced so that it references the included Bluprint.