Looking for Roller? The Official Roller Wiki is now hosted by the Apache Software Foundation.
Build and deploying Roller from source involves three simple steps: get the source, run the build script, follow the installation instructions above to deploy the results.
Read the instructions on Roller Source Code Access to find out how to get the source packages for a release or to get the latest source code directly from the source repository.
Example: get very latest Roller source into a directory called roller_trunk
% svn checkout https://svn.apache.org/repos/asf/incubator/roller roller/trunk roller_trunk
After you are done getting the source code, you can return here and move on to Step 2.
Once you have extracted the Roller source code into a directory on your system, then open up a command prompt and cd to that directory. Set the environment variable JAVA_HOME to point to your JDK and then build Roller by using either the UNIX or Windows version of the build script. This script sets up the right classpath and calls Roller's Ant build script build.xml. The build shell script invokes the Ant that is in the tools subdirectory that comes with the Roller Subversion tree (or from extracting the tools file you downloaded). If you like to drive Ant from your IDE, you should set up to use the same Ant jar and classpath that is used by the shell script.
On UNIX:
% chmod +x build.sh % build.sh all
On Windows:
C> build all
This will build Roller and will stage the Roller web application into the build/roller subdirectory.
The build subdirectory can be removed for a clean build by specifying the Ant target clean. Examine the build.xml file for additional targets.
You can simply copy the build/roller to your tomcat/webapps directory and follow the InstallationGuide to complete your deployment.
If you have problems making a build then please consult with the experts on the roller-dev mailing list. Somebody has probably encountered the very same problems that you are encountering.
After you have deployed Roller at least once manually, if you plan to do continued development, you will probably want to set up ant-based deployment to your test environment [5].
Currently, unit tests run using mock contexts and use HSQLDB for the test database. They do not require actual container deployment, and can be run as soon as you have completed a full build. To run the tests, use the Ant target "tests". Using the build script this is invoked by running
% build.sh tests
or
C> build tests
This will leave HTML test reports in files in directories under build/reports.
The ant target clean-tests will remove test build artifacts, test results, and the reports.
You can also run individual JUnit tests within your IDE. There are also two test suite's you can run: org.roller.business.TestAll for the Roller backend and org.roller.presentation.TestAll for the Roller backend.
You should have no problem running the 'tests' Ant target within Netbeans, but if you want to run individual tests some additional setup is required (TBD: document changes, if any, to project.xml)
The same goes for Eclipse. You can easily run individual unit tests in the Eclipse debugger, just make sure you include the build/tests directory in the debug classpath. See the notes below for setting up the Roller build's built-in HSQLDB database to test against.
If you run the 'tests' target, the Roller build script starts an HSQLDB database, creates the Roller database tables, runs the tests and then stops the database. If you want to run individual tests from within an IDE (for example), you'll need to: start and init the database before you run the tests and stop it when you're done. Use these Ant targets to do that:
There are some Ant targets to support the repeated deployment that occurs for developer testing. These are not intended to be used for production deployment. This section describes how to set up the deploy-tomcat target.
The deploy-tomcat target will copy the webapp files from your build staging directory to the webapps subdirectory of your Tomcat {catalina.home}. It does not set up the Tomcat context (e.g. roller.xml) or server.xml files for you. You must do this once manually. To setup to use the deploy-tomcat target, perform the following steps:
You should now be able to execute the deploy-tomcat Ant target that is in the top-level build.xml.
The main Ant build file (build.xml) pulls in XML fragment files (.xmlf extension) from the custom subdirectory that can be modified to customize the build process. One technique of maintaining a custom build is to keep your own version of the custom subdirectory in your own revision control system.
To build Roller with your customizations, checkout the desired version of Roller, rename the custom directory to custom.orig, and create a symbolic link to your custom directory, as follows:
This technique has been used to make changes to JSPs, velocity macros, themes, images, and "small bits" of code. The .xmlf files in the default custom directory provide examples of customizations you can use. (Note: You'll need a solid understanding of Apache Ant to make these kind of changes.)
The Atom Publishing Protocol (APP) is not finalalized, and Roller's implementation of it is experimental. The details of the protocol and the implementation may change in future releases without maintaining backwards compatibility. Roller's APP implementation is not suitable for production environments.
The Atom Publishing Protocol
(APP) is an application-level protocol for publishing and editing Web resources. APP is an IETF draft specification. The protocol is based on HTTP transport of Atom-formatted representations. The Atom format is documented in the Atom Syndication Format RFC
. For more information about the APP protocol and Atom, please refer to the previous links.
The Blogapps java.net project
contains sample code that illustrates how to use APP in conjunction with Roller.
The default Roller APP endpoint is: http://<server>[:<port>]/roller/roller-serices/app. The endpoint is disabled by default. To enable it, set the Roller configuration property webservices.atomprotocol.enabled to true in your roller-custom.properties, and restart the web container.
To verify that the APP endpoint is enabled, perform an HTTP GET on the default Roller APP endpoint URL:
$ ./authget.sh jtb iplanet http://localhost:8080/roller/roller-services/app
<?xml version="1.0" encoding="UTF-8"?>
<service xmlns="http://purl.org/atom/app#">
<workspace title="Jeff's Jovial Junkyard">
<collection title="Weblog Entries" href="http://localhost:8080/roller/roller-services/app/junkyard/entries">
<member-type>entry</member-type>
</collection>
<collection title="Media Files" href="http://localhost:8080/roller/roller-services/app/junkyard/resources">
<member-type>media</member-type>
</collection>
</workspace>
<workspace title="a Community Weblog">
<collection title="Weblog Entries" href="http://localhost:8080/roller/roller-services/app/a/entries">
<member-type>entry</member-type>
</collection>
<collection title="Media Files" href="http://localhost:8080/roller/roller-services/app/a/resources">
<member-type>media</member-type>
</collection>
</workspace>
...
</service>
Enabling the APP endpoint grants remote users (with the proper credentials) the ability to create, edit, and remove weblog posts. Make sure you understand the implications of this before you enable the endpoint.
The Roller APP endpoint uses HTTP basic authentication. The authenticating user must have a Roller user account. With the proper credentials, APP grants the user access to all weblogs for which they are a member.
Because AAPP relies on HTTP basic authentication, clear text passwords are transmitted over the network (base 64 encoded). If this is a concern, consider running SSL on the APP endpoint.
The protocol and implementation of the Roller Atom Admin Publishing Protocol is experimental. The details of the protocol and the implementation may change in future releases without maintaining backwards compatibility. Roller's AAPP implementation is not suitable for production environments.
The Atom Admin Publishing Protocol (AAPP) is a web service protocol that allows administration of weblog server resources, including:
The web service is implemented as XML over HTTP, employing the standard HTTP verb set: GET is used to fetch the description of an existing resource, POST creates a new resource, PUT modifies an existing resource, and DELETE deletes a resource. This is the same model employed by the Atom Publishing Protocol
(APP).
AAPP is not directly related to APP, and it is not part of the APP specification. While the features defined by AAPP were originally envisioned as part of the APP specification, the scope of the possible functions that could be encompassed in a weblog server administration protocol were too large to be considered for APP 1.0. Future versions of the APP specification should be expanded to encompass the features defined in AAPP.
By default, the AAPP endpoint is disabled in Roller. To enable it, set the Roller configuration property webservices.adminprotocol.enabled to true in your roller-custom.properties, and restart the web container.
To verify that the AAPP endpoint is enabled, perform an HTTP GET on the default Roller AAPP endpoint:
$ ./authget.sh jtb iplanet http://localhost:8080/roller/roller-services/aapp
<?xml version="1.0" encoding="UTF-8"?>
<service xmlns="http://purl.org/roller/aapp#">
<workspace title="Workspace: Collections for administration">
<collection title="Collection: Weblog administration entries" href="http://suntoy:8080/roller/roller-services/aapp/weblogs">
<member-type>weblog</member-type>
</collection>
<collection title="Collection: User administration entries" href="http://suntoy:8080/roller/roller-services/aapp/users">
<member-type>user</member-type>
</collection>
<collection title="Collection: Member administration entries" href="http://suntoy:8080/roller/roller-services/aapp/members">
<member-type>member</member-type>
</collection>
</workspace>
</service>
(This is the AAPP discovery document, which is described below.)
Enabling the AAPP endpoint should not be taken lightly. AAPP grants a remote user (with the proper credentials) many powerful administrative functions. Make sure you understand the implications of this before you enable the endpoint.
The Roller AAPP endpoint is protected by HTTP basic authentication. The authenticating user must have the Roller ADMIN role.
HTTP basic authentication transmits clear text (base 64 encoded) passwords over the network. If this is a concern, you may run SSL on the AAPP endpoint.
Every AAPP-accessible resource in the weblog server has an associated AAPP href. That href is described by the href attribute on the XML representation of the resource. The resource is accessed by executing one of the four standard HTTP verbs on the href: GET, POST, PUT, or DELETE. For example a user resource is deleted by executing a DELETE on it's href. A weblog resource is modified by executing a PUT on it's href, etc.
Not all verbs make sense for all hrefs. For example, DELETE /roller/aapp/users is not allowed. If it was to do anything, intuitively, it would delete all of the users in the weblog server, which is not something that should be possible, for obvious reasons. The sections below describe which verbs can be applied to what hrefs.
Weblog resources are described as collections of entries. For example, the weblog collection contains zero or more weblog entries. AAPP hrefs can either target a collection or an entry. For example: GET /roller/roller-services/app/users targets the user collection; it returns the set of all user entries. GET /roller/roller-services/app/users/jtb targets the user entry “jtb”; it returns a singleton entry set containing one user entry.
The protocol makes use of the standard HTTP status codes:
| Status Code | Condition |
|---|---|
| 200 (OK) | GET, PUT, DELETE success |
| 201 (CREATED) | POST success |
| 404 (NOT FOUND) | GET, PUT, DELETE resource not found |
| 400 (BAD REQUEST) | Invalid syntax in request |
| 401 (UNAUTHORIZED) | User authentication failed |
| 405 (METHOD NOT ALLOWED) | Authenticating user does not have permission to use endpoint |
| 500 (INTERNAL SERVER ERROR) | Unhandled error in server |
The service href is used to discover the hrefs for accessing weblog server resources. Clients execute a GET on the AAPP endpoint URL to retrieve the AAPP service introspection document. For example:
$ ./authget.sh jtb iplanet http://suntoy:8080/roller/roller-services/aapp
<?xml version="1.0" encoding="UTF-8"?>
<service xmlns="http://purl.org/roller/aapp#">
<workspace title="Workspace: Collections for administration">
<collection title="Collection: Weblog administration entries" href="http://suntoy:8080/roller/roller-services/aapp/weblogs">
<member-type>weblog</member-type>
</collection>
<collection title="Collection: User administration entries" href="http://suntoy:8080/roller/roller-services/aapp/roller-services/users">
<member-type>user</member-type>
</collection>
<collection title="Collection: Member administration entries" href="http://suntoy:8080/roller/roller-services/aapp/members">
<member-type>member</member-type>
</collection>
</workspace>
</service>
The introspection document contains one or more workspaces, which in turn describe collections of resources. Because of the simplicity of the protocol, there is not much to describe. An AAPP introspection collection defines the resource type being described in its member-type sub element, and an href for accessing the collection of said type. For example, in the above example, the href for the user resource type is: http://suntoy:8080/roller/roller-services/aapp/users. This is very similar to and modeled after the APP introspection document. The collection types defined by this protocol are: user, weblog, and member. AAPP implementations may support a subset of these (Roller supports all of them). The concepts of user and weblog resources are straightforward, but a member resource may not be as clear. A member resource is a triple consisting of a weblog handle, a user name, and a permission. A member resource therefore describes a user's permission for a particular weblog. These resource types will be discussed in detail below..
The default AAPP user href in Roller is: /roller/roller-services/aapp/users. Clients use this to access user resources in the weblog server.
Clients access user resources in the weblog server by applying the HTTP verbs to the user AAPP href:
User entries have the following fields:
For example:
<?xml version="1.0" encoding="UTF-8"?>
<users xmlns="http://purl.org/roller/aapp#" href="http://suntoy:8080/roller/roller-services/aapp/users">
<user href="http://suntoy:8080/roller/roller-services/aapp/users/jtb">
<name>jtb</name>
<full-name>Jeffrey Blattman</full-name>
<password>iplanet</password>
<locale>en</locale>
<timezone>US/Pacific</timezone>
<email-address>Jeffrey.Blattman@Sun.COM</email-address>
<date-created>1141863448000</date-created>
</user>
</users>
The date-created field is the output of the Java method ~Date.getTime(), which is the number of milliseconds since January 1, 1970, 00:00:00 GMT. It is returned from the GET verb; it is ignored as input to the POST and PUT verbs.
The locale field is a locale string as would be returned from the Java Locale.toString() method, which is <lang>[_<country>[_<variant>]].
The timezone field is a timezone ID string as would be returned from the Java ~TimeZone.getID() method, or as would be accepted as input to the ~TimeZone.getTimeZone() method.
The password field in only accepted as input to the POST and PUT verbs. It is never returned as output.
The default Roller AAPP weblog href is: /roller/roller-services/aapp/weblogs. Clients use this to access weblog resources in the weblog server.
Weblog entries have the following fields:
For example:
<?xml version="1.0" encoding="UTF-8"?>
<weblogs xmlns="http://purl.org/roller/aapp#" href="http://suntoy:8080/roller/roller-services/aapp/weblogs">
<weblog href="http://suntoy:8080/roller/roller-services/aapp/weblogs/junkyard">
<handle>junkyard</handle>
<name>Jeff's Jovial Junkyard</name>
<description>A place for garbage</description>
<locale>en</locale>
<timezone>US/Pacific</timezone>
<creating-user>jtb</creating-user>
<email-address>Jeffrey.Blattman@Sun.COM</email-address>
<date-created>1141863708000</date-created>
</weblog>
</weblogs>
The date-created field is only returned from the GET verb; it is ignored as input to the POST and PUT verbs. Its value is the output of the Java method ~Date.getTime(), which is the number of milliseconds since January 1, 1970, 00:00:00 GMT.
The locale field expects a locale string as would be returned from the Java ~Locale.toString() method, which is <lang>[_<country>[_<variant>]].
The timezone field expects a timezone ID string as would be returned from the Java ~TimeZone.getID() method, or as would be accepted as input to the ~TimeZone.getTimeZone() method.
The default Roller AAPP member href is: /roller/roller-services/aapp/member. Clients use this to access member resources in the weblog server.
Member URIs are slightly different than those for user and weblog resources. Where user and weblog entries are uniquely identified by a single field, member entries are identified by a user name – weblog handle tuple.
Clients access member resources in the weblog server by applying the HTTP verbs to the member AAPP href:
A member entry is a triple consisting of a user name, weblog handle, and a permission. The existence of the given member entry grants the user the given permission to the weblog. Member entries have the following fields:
For Roller, the possible permission values are LIMITED, AUTHOR, and ADMIN. LIMITED permission indicates that the user can only post draft weblog entries. AUTHOR permission allows the user to post entries to the weblog. A user with ADMIN permission can additionally modify meta information about the weblog such as the weblog name and description. For example:
<?xml version="1.0" encoding="UTF-8"?>
<members xmlns="http://purl.org/roller/aapp#" href="http://suntoy:8080/roller/roller-services/aapp/members">
<member href="http://suntoy:8080/roller/roller-services/aapp/members/junkyard/jtb">
<name>jtb</name>
<handle>junkyard</handle>
<permission>ADMIN</permission>
</member>
</members>
The name and handle fields must identify existing user and weblog resources, respectively. The permission field must be the string ADMIN, AUTHOR, or LIMITED (case is not relevant).
The Roller AAPP SDK consists of a set of classes that facilitate marshaling and unmarshaling the various entry and collection object types. Essentially, the SDK is a set of beans. XML content can be unmarshaled by constructing the various beans with an XML stream or a JDOM document / element. The bean objects can be marshaled by calling a toDocument() method that returns a JDOM document representation of the bean.
The AAPP SDK does not include utilities to assist in making wire connections to the AAPP server. Because AAPP is based on the standard HTTP verbs, there are many existing methods for accomplishing this. The Jakarta Commons HTTP Client library
offers a simple and robust solution. For examples showing how to build an HTTP client using Commons HTTP Client, see he Blogapps Examples java.net project
.
The AAPP SDK standalone JAR is not included with the Roller distribution. To build it, grab the Roller source code, and execute the aapp-sdk ant target. This builds the aapp-sdk.jar JAR file into the build/lib directory.
The AAPP SDK javadocs must also be built from the Roller source code. Execute the javadoc ant target. This builds javadocs for the entire Roller source. The AAPP SDK is under the org.roller.apache.webservices.adminapi.sdk package.
The Blogapps Examples java.net project
contains some useful utilities for interacting with the AAPP service from the command line. Specifically, consider chapter 10, which contains the scripts authget.sh, authpost.sh, authput.sh and authdelete.sh for performing HTTP basic authenticated HTTP GETs, POSTs, PUTs and DELETEs from the command line.
Roller contains several XML files that serve as example input to the AAPP service. From the Roller source tree, they can be found at testdata/adminapi-testdata.
For example, create the user "test1":
$ ./authpost.sh jtb iplanet user-test1.xml http://localhost:8080/roller/roller-services/aapp/users
<?xml version="1.0" encoding="UTF-8"?>
<users xmlns="http://purl.org/apache/roller/aapp#" href="http://localhost:8080/roller/roller-services/aapp/users">
<user href="http://localhost:8080/roller/roller-services/aapp/users/test1">
<name>test1</name>
<full-name>Test One</full-name>
<locale>en</locale>
<timezone>US/Pacific</timezone>
<email-address>test1@test.com</email-address>
<date-created>1147205191343</date-created>
</user>
</users>
The new user entry is returned. Create the weblog "test1":
$ ./authpost.sh jtb iplanet weblog-test1.xml http://localhost:8080/roller/roller-services/aapp/weblogs
<?xml version="1.0" encoding="UTF-8"?>
<weblogs xmlns="http://purl.org/apache/roller/aapp#" href="http://localhost:8080/roller/roller-services/aapp/weblogs">
<weblog href="http://localhost:8080/roller/roller-services/aapp/weblogs/test1">
<handle>test1</handle>
<name>Test 1</name>
<description>Test 1</description>
<locale>en</locale>
<timezone>US/Pacific</timezone>
<creating-user>test1</creating-user>
<email-address>test1@test.com</email-address>
<date-created>1147205414435</date-created>
<app-entries-url>http://localhost:8080/roller/roller-services/app/test1/entries</app-entries-url>
<app-resources-url>http://localhost:8080/roller/roller-services/app/test1/resources</app-resources-url>
</weblog>
</weblogs>
The new weblog entry is returned. When we created weblog "test1", we set the "creating user" of weblog to the user "test1" that we just created. Verify that the user "test1" is a member of weblog "test1":
$ ./authget.sh jtb iplanet http://localhost:8080/roller/roller-services/aapp/members/test1/test1
<?xml version="1.0" encoding="UTF-8"?>
<members xmlns="http://purl.org/apache/roller/aapp#" href="http://localhost:8080/roller/roller-services/aapp/members">
<member href="http://localhost:8080/roller/roller-services/aapp/members/test1/test1">
<name>test1</name>
<handle>test1</handle>
<permission>ADMIN</permission>
</member>
</members>
As the creating user, user "test1" has the ADMIN role for the weblog. Create user "test2", and add them as member of weblog "test1", with the AUTHOR role:
$./authpost.sh jtb iplanet user-test2.xml http://localhost:8080/roller/roller-services/aapp/users <?xml version="1.0" encoding="UTF-8"?> <users xmlns="http://purl.org/apache/roller/aapp#" href="http://localhost:8080/roller/roller-services/aapp/users"> ... $ ./authpost.sh jtb iplanet member-test2.xml http://localhost:8080/roller/roller-services/aapp/members <?xml version="1.0" encoding="UTF-8"?> <members xmlns="http://purl.org/apache/roller/aapp#" href="http://localhost:8080/roller/roller-services/aapp/members"> ...
Verify the membership of weblog "test1", and ensure the "test2" is a member with the AUTHOR role:
$ ./authget.sh jtb iplanet http://localhost:8080/roller/roller-services/aapp/members/test1
<?xml version="1.0" encoding="UTF-8"?>
<members xmlns="http://purl.org/apache/roller/aapp#" href="http://localhost:8080/roller/roller-services/aapp/members">
<member href="http://localhost:8080/roller/roller-services/aapp/members/test1/test1">
<name>test1</name>
<handle>test1</handle>
<permission>ADMIN</permission>
</member>
<member href="http://localhost:8080/roller/roller-services/aapp/members/test1/test2">
<name>test2</name>
<handle>test1</handle>
<permission>AUTHOR</permission>
</member>
</members>
Note that we asked for the set of all membership for weblog "test1" by omitting the user name from the URI.