Sunday, July 16, 2017

Creating 301 redirect assets within WebCenter Sites

This post applies to WCS 11g 11.1.1.8.0 and higher as vanity url concept was introduced with WCS 11.8 version.

What is vanity url?
Vanity url are short, pretty and easy-to-remember explanatory url which represent a unique webpage of a site. Prior to vanity url concept, you might be familiar with either URLAssembler or GST or both to generate such urls. With the introduction of vanity url, it has become very easy for editors to define vanity urls for the asset within WCS.
There are few tricks which I would like to share among the developers to leverage and make efficient use of vanity url for their clients.

Technically, these are few key features of vanity url within WCS:
  • To the core, vanity URL within WCS is nothing but a http server filter - URLRewriteFilter which actually processes incoming vanity url requests, searches for its entry in one table - WebReferences where all vanity urls are saved and further, disassembles into long url which WCS internally further processes and corresponding output is returned.
  • WCS saves all the vanity urls within one table - WebReferences (whereas WebReferencesPatterns saves the patterns if defined any)
  • Every vanity URL is a single entry within WebReferences table irrespective of the http status set: 200, 301 or 302
  • Within WCS 12c, there is an option to set default url for an asset, if an asset has many urls.
  • Target urls for 301 / 302 can be external url too, making it very easy for editors to set other webpages as target which are NOT present within WCS without any help of network / front-end server team, which is quite useful for some customers.
What can be achieved by creating vanity url within WCS?
  1. Ease of creation of pretty url for an asset which can be tested before go-live
  2. Creating url for an asset (http status is set to 200)
  3. Creating 301 url for an existing asset (http status is set to 301 / 302)
  4. Creating 301 url for a non-existing source and non-existing target webpage (custom solution to create 301 redirect for non-existing webpage within WCS)
First 3 points are straightforward concept within WCS if you have read official document and thus, its redundant to talk about them. Lets talk about the 4th point where editors want to create 301 redirect urls for an external target webpage where target website actually is not present in WCS in form of asset. It is pretty much clear that in order to create 301 redirects (3rd point above), the source or target asset should exist within WCS. But then how to create 301 redirects without target and source being within WCS. Please note, one assumption with the explained below solution is that you want to keep your domain name fixed i.e. editors want to create 301s from fixed domain to other target webpages. For e.g. if you site runs on http://www.example.com/en/home and is using Relative webroot, then all the 301s like http://www.example.com/[any-string] would work. Thus, your client should actually know what can be achieved and what cannot be before offering them such solution.

Following are the steps on how it can be achieved with little bit of development effort:
  • Create an assettype / asset definition for e.g. say Redirects_C
  • Create 2 simple attributes: source (single, unique string) and target (single, text, optional: custom URL Attribute Editor)
  • Create a flex filter or asset listener which triggers when any new or existing Redirects_C asset is saved, which in return generates an entry within WebReferences table with following column values:
    • id = ics.genID(true)
    • webroot = [webroot for the site]
    • webreferenceurl =  source string value (without spaces)
    • assetid = [current asset id]
    • assettype = Redirects_C
    • httpstatus = 301
    • redirecturl = target text value
    • redirectwebroot = [webroot for the site]
    • template = [Main page layout] -- Doesn't matter which template is used
    • wrapper = [Site Wrapper] -- Doesn't matter whichever wrapper is used
    • isdefault = 'F'
    • modifieddate = [date when asset is saved]
    • createddate = [date when first time asset was created]
    • others leave them so that NULL value is set automatically
Enable Redirects_C assettype for your site and add startmenu for it.
Task for Editor is to just add entry for source and target's value and save the asset which triggers the custom flex filter or asset listener and generates an entry in WebReferences table. For e.g. let say your site is configured to use relative webroot - "/"; create an asset with source value as "test" and target value as "http://www.example.com/test-page" and save it, custom flex filter or asset listener should create an entry within WebReferences table. When you hit the url in browser like [http / https]: [hostname] : [port]/test, it would be redirected to http://www.example.com/test-page. As the page is redirected directly to target url which is calculated within URLRewriteFilter, adding any values for template or wrapper works. Actually, for all 301 / 302 redirects, WCS never processes anything if the target is external webpage of another site.

Following is sample snippet of code on how to create an entry within WebReferences table for Redirects_C asset:

DisclaimerThe code and/or the configurations posted are not official recommendations and should be used at sole's discretion with proper testing before deploying on live WebCenter Sites systems. Cheers!! 

Saturday, April 29, 2017

Working with timezone for events

Every organization hosts various events; be it for their business growth or some internal functions or other reasons and thus, it very common requirement of client to setup event date-time within WebCenter Sites.

If your client is located only in one country, it is quite easy to setup event date-time as event is usually hosted at same geographical location, thus, you would simply create asset type and definition as needed. While displaying event on your site, you can set fixed desired timezone while formatting date-time using dateformat tags or simply using java.

But if you are dealing with multi-lingual international websites and when client wants to host events for their international counterparts also, displaying event on website pages according to user's geo-location can be a challenging and arduous task.

Although there may be many ways to deal with it and can also vary on client's requirement. I would like to present one working solution which we used in one of our project if you also have the following requirements:
  • editors should be able to set event start and end dates as they desire
  • event should be displayed in end-user's date and time according to where they are geographically located
Hence, basically there are 2 challenges for setting up event date along with timezone:
  1. Saving event date-time considering timezone within WCS
  2. Displaying event date and time on webpage according to user's timezone
Saving event datetime considering timezone within WCS
Dealing with timezone in WCS can be difficult for following reasons:
  1. While setting any date and time for a date attribute within WebCenter Sites, by default DatePicker attribute editor is displayed which provides date, time and seconds to set but lacks an option to set timezone. Thus, it is pretty sad that currently there is no out-of-the-box attribute editor available to set timezone along with date and time.
  2. Even if you set timezone as another attribute, still WCS does not consider it (for obvious reasons) and thus, you would end up manipulating the date attribute's value via flex filter or asset listener or other way.
  3. Furthermore, date attributes within WCS are saved according to the timezone of the application server where WCS is installed and thus, even if you manipulate date attribute according to 2nd step, you will face following issue: Lets suppose if your server timezone is set to UTC and one of the editor located in London sets a time 10:00 AM for an event and saves the asset. Event date is first converted to UTC by WCS and saved in database in server timezone i.e. 11:00 AM UTC. Even if the date is saved in UTC, editor sees the date according to his/her timezone set in his/her profile or automatically calculated by WCS and thus, thinks that event date & time is saved correctly. But now when editor from another location say Germany checks the same asset and verifies the event date, he/she sees the converted date according to his/her timezone i.e. 09:00 AM CEST and thinks that wrong event date or time is set by previous editor? Shouldn't it be 10 AM, why I am seeing 09:00 AM CEST ? and thus, German editor may end up editing the asset or will ask London editor to review and correct it but London editor sees the correct date set. Do you see the issue ?
How to deal with above issues in WCS ?
In order to consider timezone for an event, you would have save the event date-time along with timezone. Developing new DatePicker alike attribute editor with timezone option can be more difficult than the following way:
  1. Create 4 attributes for event definition: 2 attributes of type - date and 2 attributes of type - String. For e.g. eventstartdate and eventenddate of type - string and eventfinalstartdate and eventfinalenddate of type - date
  2. Editors will have to enter values in eventstartdate and eventenddate in some pre-defined specified format for e.g. dd-MM-yyyy HH:mm. Format can be decided with client beforehand. Also, you can add some validation on the input using some custom attribute editor. One such attribute editor is REGEX attribute editor.
  3. Editors should also specify timezone for an event via eventtimezone attribute of type - String. You can assign a pulldown attribute editor with pre-defined timezone values or can dynamically create the item list using TimeZone's method: getAvailableIds and populate them in pulldown attribute editor.
  4. When asset is saved, convert the event's start and end dates + eventtimezone into server timezone and save the value in eventfinalstartdate and eventfinalenddate respectively. You can use either flex filter or call element from PostUpdate element. If you are using Asset API to save date attribute, WCS saves date attribute in following format: yyyy-MM-dd HH:mm:ss. Note, if you are using PostUpdate way, then be sure to make eventfinalstartdate and eventfinalenddate as non-editable fields (How to do so? You can customize the element: OpenMarket/Gator/AttributeTypes/DATEPICKER by creating under CustomElements folder; to make date attribute as non-editable)
Thus, by following above steps, what have we achieved?
  1. eventstartdate and eventenddate is displayed same for all editors irrespective of their timezone set in WCS and thus, there is no conflict among editors.
  2. eventfinalstartdate and eventfinalenddate is saved always in server's timezone and importantly, as date attribute, thus, while displaying date on your webpage, always use eventfinalstartdate and eventfinalendtime.
Why are we saving same values 2 times in 2 different attributes? What do we achieve by doing so?
  • firstly, by saving attributes: eventfinalstartdate and eventfinalenddate of type - date, you can build an event search page where you can sort by date attribute easily which may have been difficult with having only string attributes: eventstartdate and eventenddate.
  • second, when displaying event's date-time, developers can use out-of-the-box dateformat tags which accepts date attribute value as input as is from assetset tags output. Furthermore, dateformat:create tag has ability to input timezone also; which is explained in next section.
Displaying event date and time on webpage according to user's geo-location
After saving event datetime according to previous step, as a developer, its already known that event dates are saved in eventfinalstartdate and eventfinalenddate as date attribute and always in server's timezone.
Thus, for displaying event, we need to:
  • find user's timezone
  • convert and display event dates in user's timezone
For finding user's timezone, there can be various ways but eventually you would have to rely on some geo-location services or other known techniques. One of the element within WebCenter Sites calculates timezone for its various core functionalities is OpenMarket/Xcelerate/Util/SetTimeZoneInSession. You can also use the same. Also, one of the popular known service is Maxmind's GeoIP; which provides quite accurate geo-lcation data and examples on finding user's geo-location data in various programming language.
One important note: If you are using WebCenter Sites 12c, GeoIP is already shipped with the product and can be used for finding user's geo-location information. In fact, we are already using GeoIP API in one of our projects running on WCS 12c for displaying personalised content according to user's geo-location.

After finding user's timezone, you can use following sample code to display the event date-time on your website pages:

I hope this post helps many other fellow WCS enthusiasts who are struggling with dates and timezone :)

DisclaimerThe code and/or the configurations posted are not official recommendations and should be used at sole's discretion with proper testing before deploying on live WebCenter Sites systems. Cheers!!

A simple code compare functionality

One of the most important aspect of any development cycle is deployment and while deployment, it is very important to note the changes don...