Category Archives: development

A Mobile Approach in Concrete5

To compliment my short post on Multi-Site deployment of Concrete5, I thought I would add to it with a candidate approach for generating a mobile site.

Assumptions

With this approach, I’m assuming a setup of a mobile site on a subdomain as opposed to sub folder.  I would consider this best practice as URLs stay consistent between the desktop and mobile site, which is encouraged in the Mobile Web Best Practices Guidelines from the W3C (http://bag.gs/gReORJ).

I’m also assuming that the desktop site has been created already.  I appreciate that this may not always be the case and that in some circles, it is encouraged to consider mobile first.

1. Set up another site on your mobile domain

Follow the steps in Multi-Site deployment of Concrete5 for your mobile domain.  In my case, I’ll use the example m.example.com but do not go back to the basic install steps at the end and do not set up your site by providing the name, URL, and database details.

2. Share the Desktop Site Content

With thanks to the great MVC design of the Concrete5 product, all the content resides in the database away from the templates and the controls, which affect the view or presentation.  Therefore, sharing the database between sites is like sharing the content.

So, open up your site.php (e.g. /var/www/m.example.com/config/site.php) and simply copy into it the contents of the site.php from your desktop site.  This means you bypass the latter install steps.

3. Themes, Controllers, and Templates

Now that we share the content, we have a blank canvas for how we would like that to appear.  I actually take a copy of the desktop site files as a starting point as I can then build into them the various mobile optimisations and at least have a starting point where all the theme templates and blocks exist so nothing breaks.

So at this point, the site will be effectively a copy of the desktop site but on a different domain.

4. Device Detection

There are different services available for device detection but they all are orientated around detection through reading the User-Agent HTTP Header.

I ended up using Tera WURFL (http://bag.gs/ewCsoc) as I didn’t want to pay for something and thought that I could manually update ok.  This is working out fine for me but your needs may be different.

Based on the simple example available on the Tera WURFL site (http://bag.gs/fKsG2X), you can extract various properties about the device and make a decision about how you want to serve that device.

I chose to categorise devices based on certain screen resolutions and other capabilities meaning that I ended up with 3 different device profiles to serve: Basic, Intermediate, and Advanced.  From this, I can make decisions based on the profile within my templates.

 

Summary

I don’t make any claims for this being the best approach but I sure would like to get the conversation going about this.  I know there are other smart ways where people change the theme based on device (in comparison to the changing of domain based on device as exampled in this post).

As mentioned earlier in the post, I like this approach as it keeps a balance of URLs between the main and mobile site.  Additionally, block templates are not tied to a theme and so the view.php or custom template for a block on the desktop version could be totally different than in the mobile version.  This also means that you can use Concrete5’s great image helper in such templates to help optimise image sizes for mobile.

Please feel free to leave comments and questions and I’ll do my best to answer or improve the post.

 

A Multi-Site Approach in Concrete5

After seeing that many were having trouble understanding how they could use a single core Concrete5 installation to run multiple sites, I thought I would write this post to provide a strawman to help facilitate the discussion of how this can be done.

I run a server in the cloud using Amazon’s EC2 service and utilise an Ubuntu server with the usual LAMP setup.

1. Core Installation Preparation

To start, I have my core Concrete5 installation files in my default web site folder:

/var/www/default/concrete5.4.0.5

I keep the version number as this allows for the many different sites to use different cores if you wish.  How this is achieved will become clear later on in the post.

This basic setup of copying files is covered on the concrete5 site (http://bag.gs/hEWOT9) so I’m not going to repeat that here but it is important to say just copy the files for now.

N.B. Don’t go to the installed location in a browser yet – just copy the files.

2. Set up the domain that you want to host

This means that you can set up a separate virtual host in Apache or however which way you’d like to.  A search (http://bag.gs/heaC2L) will surely find you some assistance here.

The end result will be a virtual host that corresponds to your domain (e.g. www.exampledomain.com) and a separate directory from which that site is served on your server.  In my case, this directory is:

/var/www/example.com

N.B. I’m assuming that you’ve purchased your domain and have all the right DNS entries set to point to your server.

3. Set up site specific structure

This step is reasonably simple.  We are going to copy the entire contents of the core installation folder (concrete5.4.0.5 in my case) over to the new site directory so that we have the following:

/var/www/example.com/blocks
/var/www/example.com/concrete
/var/www/example.com/config
...
/var/www/example.com/updates

This copies what are in the most part empty directories and the inner concrete.  The root index.php is important as well as the couple of files in the config directory so make sure you take those across.

As concrete5 is well designed, the guys who have created the product have nicely permitted the extension of almost everything through utilising the directory hierarchy.  This means that as site developers, we should never touch the content of the internal concrete directory.  In the above case, the /var/www/example.com/concrete directory.  Consider it sacred!

If we obey this principle of not messing with anything in the core concrete folder, which helps us all upgrade, then you would notice that there is no value in that the …/example.com/concrete folder being a copy of the …/default/concrete5.4.0.5/concrete folder and you’d be correct.

Therefore, we are going to delete the /var/www/example.com/concrete directory and replace it with a symbolic link.  It is the symbolic link that allows us to point to different cores for different sites.

The syntax for the symbolic link when in the /var/www/example.com directory is:

...:/var/www/example.com$ ln -s ../default/concrete5.4.0.5/concrete concrete

Your Done!

Seriously, that’s all.  You can then pick up the basic setup (http://bag.gs/hEWOT9) at the point where you navigate to the new site, enter the site name, URL, and Database settings and away you go.

This small amount of preparation allows you to scale a single core instance of Concrete5 through using separate databases.

It would be great to get people’s views on this as I’m sure there are areas to improve or things that I’ve not considered.  Therefore, please leave a comment with your feedback.

Moving Open Text Delivery Server to Common Search

As part of the small team behind the Solution Exchange, I was somewhat dreading the day when I had to change the internal search engine over to Open Text Common Search on the Web Site Management Delivery Server.

However, in absolute honesty, this was not the issue of complex configuration that I was expecting and I will explain the steps I took.

The Delivery Server Common Search Connector

  1. The first step is to install the Open Text Common Search product.  I was fortunate enough to have this already in our infrastructure so didn’t need to do this step.
  2. Assuming the Common Search is installed, you can log into Delivery Server, navigate to connectors > Search Engines > Administer and click the import button.  Version 10.1 of Delivery Server has a pre-configured connector that you can use.  Click the OTCommonSearch link to import the connector.
  3. Change the URL of the Common Search Server to the IP of your Common Search machine.
  4. Change the “Incoming directory of indexing jobs” to a shared folder.  This is a path as seen by the Delivery Server.  I’ve chosen to place this on the local machine of the Delivery Server and share that with the Common Search machine.
  5. Change the “Incoming directory of Common Search server” to point to the same directory as above but from the perspective of the Common Search machine.  I initially had problems here as the Delivery Server and Common Search were on different Domains.  We changed this anyhow to reflect better practice in our setup.
  6. Create the shared folder if you haven’t already and make sure both the Delivery Server and Common Search have read/write access.
  7. You’re done!

It was really that easy! (well, if I discount the delays due to not being able to share directories effectively across Windows Domains at first).

Finally, it is worth pointing out the tweaks I made to my queries for the new Search Engine.

When searching specific groups, you can now use the syntax:

group:<ds_group_name>

and

attributeName:'[#request:attributeExample#]'

for attributes.

Admittedly, I didn’t need to do anything more complex than this so there were not a lot of queries to change.

There may be more complex example out there but the key message is to start planning your changeover now as it might just be easier than you think!

As always, please leave your questions or comments.

When jQuery callbacks don’t appear to work in IE7

I recently encountered a frustrating issue where a callback function from a jQuery .get() call was not being fired in IE7 but was working in other browsers including IE8.  I had a hunch that it was related to the data object being used to transport the returned JSON but wasn’t sure how.

After hitting my head against a brick wall and following through a number of dead-end forum thread’s, I worked it out the old fashioned way, which is why I thought I’d write up my findings in this short article.

I was making a request using the .get() jQuery function that was returning JSON, which was perfectly valid (I checked with JSONLint.com). However, upon checking the JSON that was being returned when using the awesome Chrome Developer Tools, I saw a nicely formatted JSON string in the response content… and that was the problem – it was a nice human readable structure… IE7 doesn’t like that!

Removing all redundant whitespace on the server side when forming my JSON string resolved my issue and my callbacks were once again being called within IE7 along with all other browsers.

Leave a comment if you have any questions.

IIS7, Tomcat & Application Request Routing

Further Update: 27nd June 2011

Another update on this topic. If you were making the use of custom error pages in IIS7 and you implemented the below update, you may have noticed that the custom error commands are no longer being adhered to. To change this, you need to set up custom error pages at a site level by choosing your site, selecting “Error Pages”, then “Edit Feature Settings” from action menu and then “Custom error pages”.

Important Update: 22nd June 2011

On page 2 of this article (How To Configure IIS 7.0 and Tomcat with the IIS ARR Module), there is a key step that I failed to observe when I wrote the original post below.  The step in question is the enablement of the (reverse) proxy server after the ARR install.  By doing this, you are able to apply rewrite rules at the site level — something I wasn’t able to achieve originally, which meant that the routing rules within my server farm were somewhat overloaded.

With this setting enabled, I can leave a single delegation rewrite rule at the server farm level, telling IIS to delegate HTTP requests of a certain pattern but leave the rewrite rules that are there for beautification at the desired site level.  This is a much tidier and more scalable approach.

One gotcha that you need to be aware of is that the rewrites at the site level need to be absolute URLs.  Therefore, you could be tempted to place the host of a single tomcat instance that lay behind IIS direct in here and it would work fine but why not allow for a little future proofing and use localhost within all absolute URL site level rewrites, which isolates the rewrites used for masking ugly application URLs and delegates the job of request delegation to the server farm?  This approach would allow for the server farm config to be used to bring other tomcat instances online or taken offline for maintenance etc without having to change the site level configuration.  In other words, it keeps the various areas of the IIS7 interface focused on the job in hand allowing for easier administration.

Please keep this update in mind as you read the otherwise unchanged original post below.

Regards,

Dan

After many years of using the Tomcat Connector (http://tomcat.apache.org/connectors-doc/) when setting up Tomcat behind IIS, it is now time to say goodbye.

This is the conclusion that I’ve come to after having some particularly significant challenges using IIS7 on a 64bit Windows 2008 machine.

The traditional approach I’ve used in the past has been to utilise the Tomcat Connector, which is implemented as an ISAPI Filter, to delegate requests from IIS through to Tomcat.  This has worked great for me in the past and was the subject of a previous article (http://bit.ly/lp6zW) but the 64bit system threw in a couple of additional challenges that weren’t so easy to get around.

The problems faced led me to discover Application Request Routing (ARR), an official extension for IIS7, which allows you to define the delegation of requests to servers sitting behind the IIS instance.

What is particularly nice with this extension is the way in which it facilitates the former approach within the GUI, making it easier to understand what is being delegated.  The approach however, is similar to the ISAPI filter approach – delegating based on URL path patterns.

The following takes you through an overview of how to set this up:

1. Install ARR

You can obtain the appropriate install for the ARR IIS7 extension at http://www.iis.net/download/applicationrequestrouting

Once installed, the ‘Server Farms’ node indicates that it has installed correctly as indicated in the picture below.

ARR Install

The Server Farms node is seen if ARR is installed correctly

A number of  modules are added as part of this extension.  You can find the details of these from the same ARR link (http://www.iis.net/download/applicationrequestrouting)

2. Create Server Farm

Although the concept of a ‘farm’ of servers may be overkill for our needs of delegating HTTP requests through ISS7 to Tomcat, we shall never the less set up a farm containing one server – our Tomcat instance.

To do this:

  1. highlight the ‘Server Farms’ node in the left panel of the IIS7 Management Console .
  2. Choose ‘Create Server Farm’ from the right hand side action menu.
  3. You will be prompted for a name for the farm.  For my  needs in setting up the Open Text Delivery Server behind IIS7, I gave the farm the name ‘Tomcat – Delivery Server’.ARR Server Farm Name
  4. You will then be prompted to set up a server in the farm.  In our case, we are just going to select the localhost instance of Tomcat running on port 8080. To specify the port, open the ‘Advanced settings’.  Strangely, there appears to be no easy way to edit a servers port once set up so make sure you are correct, otherwise you will have to delete and add a new server.

    ARR Add Server

    Make sure you open the Advanced settings to edit the port number

3. Configure the Routing Rules

Now that we have informed IIS7 about the server that sits behind, we need to let it know how we wish to delegate HTTP requests to it.  To do this, we choose the newly created Server Farm in the left hand panel and select the Routing Rules feature.ARR Routing RulesWithin here, we have a few options.  I’ve chosen to keep the defaults of having both checkboxes checked and have no exclusions set as I am delegating this responsibility to the URL Rewrite Rules.

From here, you can add and modify the rewrite rules defining how requests are delegated using the ‘URL Rewite’ link in the right-hand action panel.

In my case, I chose to change the default rule that was set up for me to a regular expression as opposed to the wildcard default.  However, I only chose this due to personal preference.  The pattern I used for this rule is:

cps(.+)

and I ignore the case.

Finally, I have no Conditions or Server Variables to take note of in my scenario although they can easily be added here, so I conclude the rule by setting the action to ‘Route to Server Farm’ and chose my ‘Tomcat – Delivery Server’ farm with a path setting of

/{R:0}

This passes all URL path info through to Tomcat.  I also choose to stop processing of subsequent rules

4. Refine Rules for your Environment

Lastly, in my setup, I’ve added the following further rules to refine how my site is served through IIS7:

Delegate .htm and .html requests:

Pattern - ([^/]+.html?)
Action path - /cps/rde/xchg/<project>/default.xsl/{R:1}

Delegate .xml requests:

Pattern - ([^/]+.xml?)
Action path - /cps/rde/xchg/<project>/default.xsl/{R:1}

Delegate default home page

Pattern - ^/?$
Action path - /cps/rde/xchg/<project>/default.xsl/index.htm

Summary

Although this approach of using IIS7 in a reverse proxy capacity may not benefit from the efficiencies of the AJP protocol used by the Tomcat Connector, the impact in most sites will be negligible.  In exchange, you have a way of Tomcat and IIS7 working together in a way where the GUI of the IIS7 Management Console helps admins define and understand what is happening.  The ISAPI Filter approach is often not so visible because of the broad nature of what ISAPI modules can provide but also due to the configuration required outside of the IIS7 Management Console.

As always, if you have any questions, leave a comment.

Progressive Enhancement via AJAX

I have recently been curious on how a normal web site with various posts and page reloads could be improved through AJAXifying it (yes, I did mean to say that – you get what I mean) – i.e. introduce AJAX calls to improve the smoothness of the user experience and minimise page reloads in key areas of a site.

In particular, my understanding of JS frameworks such as jQuery, based on the examples I’d seen, meant that form submissions were tied to specific knowledge of the form that the event was bound to.  For instance, when you bind the onSubmit event to a particular form, the many examples out there show functions that then pull content from the form through something like the following selector:

var inputVal = $('form input[name=user]').val();

This is OK for specific cases like a registration or contact us form that tends to be unique on a page but what if there were multiple similar forms on a given page and you simply wanted to submit all the form data to the same URL as before with the standard form submission but instead through an AJAX HTTP Request?

Somehow, having this sort of specific knowledge from within the handler function didn’t feel right to me, so I set off with the goal to find out how I can get the related form data from the info that is passed to the event function handler by default, without any extra manual passing of data etc.

This led me to the jQuery Event Object (api.jquery.com/category/events/event-object/), which through the target property provides a reference to the DOM element that initiated the event a.k.a. the element that I bound the event to.  This provides the key piece of information that I was missing.

Let’s take the following HTML code snippet that has 3 similar forms on a single page as an example:

<form name="form1" action="/getSomething" method="post">
  <input type="text" name="input1" />
</form>
<form name="form2" action="/getSomethingElse" method="post">
  <input type="text" name="input2" />
</form>
<form name="form3" action="/getAnotherThing" method="post">
  <input type="text" name="input3" />
</form>

Taking the above example, we can bind the event to all three forms in one go with the following:

$('form').submit(getSomethingFunction);

As we know we are passed the event object to the handler function, we can extract the form specifics being used once within the function:

function getSomethingFunction(eventObject)
{
    var formName = eventObject.target.getAttribute('name');
    var formAction = eventObject.target.getAttribute('action');
    ...  
    return false;
}

We can then initiate our post request using the jQuery serialize() function (api.jquery.com/serialize/):

function getSomethingFunction(eventObject)
{
    var formName = eventObject.target.getAttribute('name');
    var formAction = eventObject.target.getAttribute('action');
    $.post(formAction,$('form[name='+formName+']').serialize(), callbackFunction,'json');
    return false;
}

As you can see, through the power of jQuery, it simplifies this type of challenge with only a small amount of easy to follow code, allowing you to re-use the same (pre-AJAXified) server side code.

In my real case, I added a ?format=json to the post URL when calling via AJAX so that my server side PHP script knew that it didn’t need to send a full HTML page back as a response and instead sent a JSON formatted success/failure message back.

From this small investigation, I’m now interested in understanding what frameworks are out there that facilitate this type of progressive enhancement approach and utilise a widely adopted JS library such as jQuery.  Please leave a comment if you have any tips or advice.

Open Text Delivery Server with a Front Controlling Web Server

Overview

This post discusses the best practice of deploying the Open Text Delivery Server in an optimal way alongside a front controlling web server.

Delivery Server is a dynamic web server component that has strengths in coarse grained personalisation and dynamic behaviour as well as system integration.  Therefore, as it is housed within a Servlet Container, it is not the ideal location from which to serve static content (unless you wish to maintain a level of access control over the static content).

Leveraging the use of a front controlling Web Server, facilitates an optimised site deployment as web servers such as Microsoft’s IIS or Apache’ HTTP Server can be utilised for delivering static content in an optimised way.  For example, it is possible to easily configure a far future ‘Expires’ header on a given folder and therefore its content within either Apache or IIS, which promotes the caching of content in a user’s browser, which reduces page load times.  Another example is in the use of mature compression features within such web servers.  Although these examples can be achieved with some Servlet Container’s, it is certainly not straight forward and doesn’t necessarily make sense from an architectural perspective.

It is for this architectural reason, that best-practice dictates that we delegate only the relevant HTTP requests to Delivery Server.  In most cases, this means that Delivery Server is delegated requests for .htm and .xml resources.  The rest can be served from the front controlling web server (or better still a CDN).

This article provides a high-level overview of what to set up.  Depending on feedback, I may post further posts on the details of each step.

Delegating Requests from the Web Server to Delivery Server

This step can be easily achieved using the Tomcat Connector for both IIS and Apache. To find out more see the Tomcat Connector documentation here: http://bit.ly/at1w8G.

This connector uses the Apache JServ Protocol, which connects to port 8009 by default on Tomcat and is optimised to use a single connection between the Web Server and the Delivery Server for many HTTP requests.  Therefore, this represents a better option than using reverse proxy functionality within the Web Server.

If we take a typical Delivery Server install (i.e. the reference install using Tomcat), a page can be accessed with something like the following URL:

http://<host>:8080/cps/rde/xchg/<project>/<xsl_stylesheet>/<resource>

where resource could be any text based file like index.html or action.xml.

The result of correctly installing the Tomcat Connector means that we can access that same resource but through the Web Server on port 80 and not direct to the Tomcat instance on port 8080:

http://<host>/cps/rde/xchg/<project>/<xsl_stylesheet>/<resource>

Many confuse this step with URL rewriting or redirecting as the Tomcat Connector is often called the Jakarta Redirector.  Therefore, I choose to differentiate by saying that this delegates HTTP requests between the two systems and nothing more.

In every install, I have always used the defaults in the workers.properties file and just used the following rule in the uriworkermap.properties file:

/cps/*=wlb

URL Rewriting

Due to the effort of setting up delegation, deciding which HTTP requests should be forwarded to Delivery Server is a simple matter of performing some URL rewrites.

As we have decided to use a mature Web Server, there are best practice ways to achieve this.  In IIS6, HeliconTech (http://bit.ly/bgJEF6) created a very useful ISAPI filter which ports the widely adopted Apache mod_rewrite (http://bit.ly/cfvuLD) functionality.  For both of these, the same rewrite rules can be used.  The following provides a couple of typical examples:

# Default landing page redirect
RewriteRule ^/$ /cps/rde/xchg/<project>/<xsl_stylesheet>/index.htm [L]
# Rewrite to delegate all *.html or *.htm HTTP requests to Delivery Server
RewriteRule ^/?.*/(.+.html?)$ /cps/rde/xchg/<project>/<xsl_stylesheet>/$1 [L]
# Rewrite to delegate all *.xml HTTP requests to Delivery Server
RewriteRule ^/?.*/(.+.xml)$ /cps/rde/xchg/<project>/<xsl_stylesheet>/$1 [L]

Those of you who are well versed in regular expressions will see that the last two rules could be combined but I tend to leave them separate to aid readability.

The beauty of using regular expressions in this way is that you can actually create useful SEO benefits to your site also. Take for example the following rule:

RewriteRule ^/?.*/([0-9a-zA-Z_]+)$ /cps/rde/xchg/<project>/<xsl_stylesheet>/$1.htm [L]

This rule maps a URL with many apparent subdirectories to the Delivery Server file.  This means that you can publish a page with a “virtual” path within the Management Server which appears to a browser (and search engines) as something like the following:

http://<host>/this/is/a/descriptive/directory/structure/page.htm

and yet this maps to:

/cps/rde/xchg/<project>/<xsl_stylesheet>/page.htm

IIS7

Being a Microsoft product, IIS7 has some quirks with regards to the rewriting (of course), which I explained in a previous post: http://bit.ly/lp6zW.

Summary

This approach has led to many successful installations where sites could additionally be optimised for SEO and page load.

Fun and Games with IIS7 and Tomcat Connector (Jakarta)

I needed to run Tomcat behind IIS and delegate html page requests as well as xml page requests from IIS 7 through to Tomcat.

As I had done this a number of times with IIS6 and Helicon’s rewrite tool, I thought this would be easy… Oh no.  I was wrong.

Therefore, here are a few things to be aware of:

  • Make sure you have installed the Tomcat Connector OK.  I found this site to be useful here for the Tomcat Connector install on IIS 7: http://www.iisadmin.co.uk/?p=72
  • Install the ‘URL Rewrite’ module within IIS 7.  I didn’t do this myself, not because it was difficult… I just simply didn’t do it and would guess there is enough info on how to do this.
  • Configure all rewrite rules at the server level and not at the individual site level.  This is because there is some issue around chaining an HTTP request through an ISAPI filter like the Tomcat Connector and then the URL rewrite module or vice versa.  I even tried another ISAPI based rewriter like the one from Helicon (http://www.helicontech.com) resulting in the same challenge that the rewrites and redirect (delegation – not to be confused with a 301 type redirect) worked independentlybut not together.
  • The syntax for the rewrite rules is different from Apaches mod_rewrite – e.g:
  1. ^/?.*/(.+.html?)$ would normally handle input urls like /index.htm or /level1/level2/index.htm but this was not liked by the URL Rewrite module in IIS 7.  What worked instead was ([^/]+.html?).
  2. Remember to use {R:1} syntax for getting the back references instead of $1 etc.
  3. Remember to use conditions if you have multiple sites in the same instance utilising the {HTTP_HOST} and {SERVER_PORT} strings.

Let me know if you found this useful or if there are other useful references to add into this.  I personally found it difficult to dig up something similar.