Hello all. If you remember back some time, there were some writings on the Roller mailing list concerning multi-domain support in Roller (This link might help refresh your memory: http://mail-archives.apache.org/mod_mbox/incubator-roller-dev/200603.mbox/[EMAIL PROTECTED]).
I am writing now because we are quite close to a production release and we are now hoping that our work can be integrated as a part of the Roller project. Our hope is that you will see that this extension, by enabling larger scale deployment of Roller, is an extension that might bring roller to even more widespread use. As a guideline when we designed and implemented this extension, we made an effort to modify as little as possible of the roller source code. This was both to ease upgrades and to make it possible to easily use Roller with or without multi-domain support. However, you are not forced to accept all our patches. In addition to extending Roller with a multi-domain model, we have also: * done a translation for both Norwegian languages (nynorsk and bokmål) * and we have made some improvements to the Roller source to facilitate our extension, (basically these include better support of the Norwegian languages, and converting <c:out ... to <c:url where that was needed). These changes don't alter Roller's behavior and does not introduce additional complexity. As a minimum we hope that these two categories of patches will be included. The patches and user documentation are provided for review at: http://users.linpro.no/kjellm/roller-patches.tar.bz2 http://users.linpro.no/kjellm/userguide_for_multidomain_en.pdf I have included below a document describing the changes that has been done. This document also enumerates all the patches with some commentary on why they are needed. Best regards -- Kjell-Magne Øierud Systems Consultant Linpro AS -- Multi-Domain Support In Roller Henning Kulander and Shervin Asgari June 27th 2006 ABSTRACT This document explains what changes Linpro made to Roller 2.1 in order to use it in a large scale deployment for 26 (currently) newspapers in Norway. It also explains how the system is used. INTRODUCTION Linpro is a consulting company in Norway that specialize in services running on Linux. We were hired by a company in Norway that owns a large number of news papers (50+). They had used some time evaluating different blog solutions, and had more or less decided to use Roller. The biggest challenge was that they needed to serve separate blog servers for all the different news papers, with separate lists of blogs, the possibility to use the same blog name and handle on different blog servers etc. This was a problem they had found no adequate solution for in any current blog systems. So it was decided to add this to Roller. One alternative would be to install Roller 50 times with 50 databases and try to administer them all. The requirements was: * Enable use of same handle for different blogs on different domains * Enable use of same blog on different domains (shared blog), and again the blog should blend in with the news site you are currently viewing. * An administration interface to administer the domains * Enable different look and feel for each news paper to make the blog "blend in" with the news site * A front page (planet) with latest blog entries from current domain Requirements not yet met are: * An administration interface to let a selected user in a domain administer his own domain with related blogs. * Enable searching in all blogs on the current domain * Control what domains a user is allowed to log in to THE SOLUTION After some consulting with people on the Roller mailing list it was decided to go for a filter based solution. This would not require deep changes in the Roller code base, so it would be easier to develop on our own. We have chosen to run Roller under /blog/ instead of /roller/, as this is easier for the users. The filter filters everything coming to /blog/domain/, finds the right website in an association table and forwards the request to the normal servlet in the traditional form (/blog/page/handle). In addition it creates wrappers for the request and response. The point of the wrappers is to override URLs and redirects so the user is not moved back to the main Roller-site (The real address for the Roller server). The URLs are written back to the /blog/domain/ form, and then re-translated from that form to the form seen by the users (http://domain/blog/*) by a URLRewriteFilter. The job of translating URLs like http://domain/blog/ to the /blog/domain form is left to mod_rewrite in the Apache web server. To enable this functionality, a DomainManager was added, and three new tables with corresponding POJO-implementations (only two are currently in use). The DomainManager needed to be added to RollerManager so it can be used like the other managers. The URLs are picked up by DomainFilter, which creates wrappers for the Response and Request objects. The DomainFilter is also responsible for finding the correct blog by inspecting the handle given in the request, finding this handle in the DomainWebsite table, which points to the Roller Website object for the blog. The request is then forwarded to that website using its old handle and a normal Roller-URL. In addition the URLs generated throughout Roller needs to be sent through encodeURL in the wrapper for Request and Response. This resulted in quite a few changes in velocity macros. All these changes consists in sending the URL through pageHelper.strutsUrlHelper(). This in turn calls the encodeURL method in the wrapper. In addition, SearchServlet and *WeblogCalendarModel needed to be changed. SearchServlet needs to use another context initializer so the pageHelper object is available in the velocity scripts, WeblogCalendarModel needs to call encodeURL on the URLs they create. This enables all URLs to be rewritten to the form /roller/domain/(service)/(domain)/(handle) on the way out, so the user still thinks he is on the domain. In addition, these changes enables the use of UrlRewriteFilter in Roller, so you can do whatever magic this can do. I use UrlRewriteFilter to rewrite the /roller/domain/(service)/(domain)(handle) URLs to the more user friendly form of http://(domain)/(service)/(handle). The rewrite patches will also enable other forms of URLrewriteFiltering that other users might require. This takes care of the first two requirements. The third requirement was solved by creating a new interface and adding it to the admin-menu. This interface gives the administrator a list of available domains, and the option to edit them, or create a new domain. A new domain needs a domain name, which is the domain name the user sees in the URL, ie (www.mynewspaper.no <http://www.mynewspaper.no/>). When the administrator edits this domain, he can add websites to the domain and give it a handle in this domain. This list is then used by the filter to find the website. To solve the fourth requirement, a new theme was made. This theme is very specific to our customer, and will therefore not be made publicly available at this time. The way the theme work is to use the $host variable in the velocity script to dynamically include HTML-components unique for each news paper. These components are in turn downloaded from the news sites periodically using a server side script. These components includes CSS, menu icons etc. from the different news sites. This theme is then used as the default theme on all blogs. The look of the theme will be different depending on the included components. The Roller planet did not meet our requirements. It did not seem to be easily themeable, it was difficult to get it running stably and it seemed to be quite difficult to enable a domain model here. We did an evaluation of different planet solutions, and chose to use Planetplanet in our setup. This seemed to be a flexible and light-weight planet that would serve our needs quite well. The planet is available as a front page on /blog/, so this is the first thing the user will see when they enter the blog section of the news paper. This is handled by apache by overriding ^/blog(|/|/index.jsp)$ and sending requests to a static html generated by planetplanet. The configuration for planetplanet is automatically generated by a script that reads the domainwebsite and domain tables from the database, this script also generates cron-scripts that are used for updating the planets and fetching HTML-components for the themes. So the result is one planetplanet for each domain in Roller, containing the websites for this domain and the domains native look. In addition there was a requirement that the solution be available in the two major written languages in Norway (Bokmål and Nynorsk). Our customer translated the properties file to these languages, and we integrated them. But to ensure that the language is controlled by the page a viewer is watching, and not by that users profile, we had to make a tiny patch for LanguageUtil.java. We are also using email addresses for login, so the input field had to have a larger max size. CAVEATS This solution is now considered to be in a production ready state. But there are still things that could be improved. The most urgent need for improvement is to add a new administration level for domain administrators. This could be done by adding a new userrole called "domainadmin". A domain administrator would then be associated with his domain through domainuser, and with the role through userrole. A user with these associations whould then be able to administer what blogs are available in his domain. This job is now left to a central administrator. The procedure to create a new domain with a set of blogs is now to create the users as the administrator user, create blogs for these users, create the new domain, associate the blogs with the domain, link users to the domain and add an editor to the blog (The latter is OPTIONAL). This is quite time consuming, as the administrator needs to go through many different web forms. And login as the created users to create the blogs for them. This procedure needs to be simplified so the administrator can just create the domain and a domain administrator. The domain administrator must then be able to create new blogs with a new user as owner in one simplified form, where all the administrator needs to enter is User full name, email-address (used as username), password, Name of blog and handle. The rest will get default values which can be changed by the users at a later time. The news papers have legal responsibility for the content they publish. The editor for the news paper must therefore be able to remove or edit entries in any blog under his domain in case a blog contains material that could result in legal issues. To solve this, we have enabled the administrator to link users to a specific domain. This adds the user and domain in the domainuser table. The interface lists all users, and allow the administrator to choose which user he wants to add to the domain. Subsequently, when accessing the 'add editor' interface, only the users linked to the domain in question is viewed for election. This is to ensure that only users from the specific domain is allowed to be an editor. THE PATCHES USED IN THIS SOLUTION Patches that enable URLs to be rewritten: (Add context to be used later for URL rewrite) ./src/org/roller/presentation/search/SearchServlet.java.patch (Rewrite URLs) ./src/org/roller/presentation/weblog/tags/WeblogCalendarModel.java.patch ./src/org/roller/presentation/weblog/tags/BigWeblogCalendarModel.java.patch ./src/org/roller/presentation/website/actions/UploadFileFormAction.java.patch ./web/theme/bannerStatus.jsp.patch ./web/WEB-INF/classes/navbar.vm.patch ./web/WEB-INF/classes/searchresults_day.vm.patch ./web/WEB-INF/classes/searchresults.vm.patch ./web/WEB-INF/classes/website.vm.patch ./web/WEB-INF/classes/flavors/rss.vm.patch ./web/WEB-INF/classes/comments.vm.patch ./web/WEB-INF/classes/rssmacros.vm.patch ./web/WEB-INF/classes/weblog.vm.patch ./web/weblog/WeblogEdit.jsp.patch ./web/weblog/WeblogQuery.jsp.patch ./web/weblog/CommentManagement.jsp.patch ./web/website/UploadFile.jsp.patch ./web/website/YourWebsites.jsp.patch (Rewrite URLs and make description translatable:) ./contrib/plugins/src/org/roller/presentation/velocity/plugins/readmore/ReadMorePlugin.java.patch ---------------------------------------------------------------------- Patches that add new tables and a domain manager (DB stuff): (Add the new database tables:) ./metadata/database/droptables.sql.patch ./metadata/database/createdb.vm.patch ./metadata/database/hibernate/hibernate.cfg.xml.patch ./src/org/roller/pojos/DomainWebsiteData.java ./src/org/roller/pojos/DomainData.java ./src/org/roller/pojos/DomainUserData.java (Add DomainManager:) ./src/org/roller/model/Roller.java.patch ./src/org/roller/model/DomainManager.java ./src/org/roller/business/DomainManagerImpl.java ./src/org/roller/business/RollerImpl.java.patch ./src/org/roller/business/hibernate/HibernateRollerImpl.java.patch ./src/org/roller/business/hibernate/HibernateDomainManagerImpl.java ---------------------------------------------------------------------- Patches that enable the use of the domain model (ie. filter incoming requests under /domain/ and rewrite URLs on the way out: (A servlet filter to filter incoming domain requests, with helper classes:) ./src/org/roller/presentation/filters/DomainFilter.java ./src/org/roller/presentation/filters/DomainFilterRequestWrapper.java ./src/org/roller/presentation/filters/DomainFilterResponseWrapper.java ./src/org/roller/util/DomainUtil.java (Rewrite outgoing URLs:) ./contrib/lib/urlrewrite-2.6.0.jar ./web/WEB-INF/urlrewrite.xml ./metadata/xdoclet/filters.xml.patch ./metadata/xdoclet/filter-mappings.xml.patch ---------------------------------------------------------------------- Patches that add a configuration interface that lets the administrator administer the domain model: ./src/org/roller/presentation/website/actions/DomainWebsiteAdminAction.java ./src/org/roller/presentation/website/actions/DomainAdminAction.java ./web/website/domainAdminDeleteOK.jsp ./web/website/domainwebsiteAdminEdit.jsp ./web/website/domainAdmin.jsp ./web/website/domainwebsiteAdminDeleteOK.jsp ./web/website/domainAdminEdit.jsp ./web/website/domainAdminAddDomainUser.jsp ./web/website/domainEditor.jsp (Add some constants:) ./src/org/roller/presentation/RollerRequest.java.patch (Add menu items and bind JSPs to actions:) ./web/WEB-INF/tiles-defs.xml.patch ./web/WEB-INF/admin-menu.xml.patch ./metadata/xdoclet/global-forwards.xml.patch (New properties used by domain administration interface:) ./web/WEB-INF/classes/ApplicationResources.properties.patch ---------------------------------------------------------------------- General patches used to fix problems we encountered: (Add norsk and nynorsk as available languages:) ./src/org/roller/presentation/velocity/LanguageServlet.java.patch ./web/WEB-INF/classes/ApplicationResources_nn.properties ./web/WEB-INF/classes/ApplicationResources_no.properties (Use language from current blog as default:) ./src/org/roller/presentation/LanguageUtil.java.patch (Use Asynchronous GET when gettin list of users, fixes Firefox bug:) ./web/theme/scripts/ajax-user.js.patch (Allow 255 character usernames to handle long email addresses:) ./web/website/UserAdmin.jsp.patch
