jQuery Datepicker Accessiblity

Primefaces has not updated its datepicker for accessibility but we can fix it by using


/**
*
*/
function handleDatepicker(xhr, status, args) {
renderDatePicker();
}

function renderDatePicker() {

// Add aria-describedby to the button referring to the label
$('.ui-datepicker-trigger').attr('aria-describedby', 'datepickerLabel');
dayTripper();
return false;
}

function dayTripper() {
$('.ui-datepicker-trigger').click(function(event) {
var currobj = $(this);
setTimeout(function() {
var today = $('.ui-datepicker-today a')[0];

if (!today) {
today = $('.ui-state-active')[0] ||
$('.ui-state-default')[0];
}
// Hide the entire page (except the date picker)
// from screen readers to prevent document navigation
// (by headings, etc.) while the popup is open
$("main").attr('id', 'dp-container');
$("#dp-container").attr('aria-hidden', 'true');
// $("#skipnav").attr('aria-hidden','true');

// Hide the "today" button because it doesn't do what
// you think it supposed to do
$(".ui-datepicker-current").hide();

today.focus();
console.log($(this));

datePickHandler(currobj);

}, 0);
});
return false;
}

function datePickHandler(element) {
var activeDate;
var container = document.getElementById('ui-datepicker-div');
//var input = document.getElementById('datepicker');

$(container).find('table').first().attr('role', 'grid');

container.setAttribute('role', 'application');
container.setAttribute('aria-label', 'Calendar view date-picker');

// the top controls:
var prev = $('.ui-datepicker-prev', container)[0],
next = $('.ui-datepicker-next', container)[0];
// This is the line that needs to be fixed for use on pages with base URL set in head
next.href = 'javascript:void(0)';
prev.href = 'javascript:void(0)';

next.setAttribute('role', 'button');
next.removeAttribute('title');
prev.setAttribute('role', 'button');
prev.removeAttribute('title');

appendOffscreenMonthText(next);
appendOffscreenMonthText(prev);

// delegation won't work here for whatever reason, so we are
// forced to attach individual click listeners to the prev /
// next month buttons each time they are added to the DOM
$(next).on('click', handleNextClicks);
$(prev).on('click', handlePrevClicks);

monthDayYearText();

$(container).on('keydown', function calendarKeyboardListener(keyVent) {
var which = keyVent.which;
var target = keyVent.target;
var dateCurrent = getCurrentDate(container);

if (!dateCurrent) {
dateCurrent = $('a.ui-state-default')[0];
setHighlightState(dateCurrent, container);
}

if (27 === which) {
keyVent.stopPropagation();
return closeCalendar(element);
} else if (which === 9 && keyVent.shiftKey) { // SHIFT + TAB
keyVent.preventDefault();
if ($(target).hasClass('ui-datepicker-close')) { // close button
$('.ui-datepicker-prev')[0].focus();
} else if ($(target).hasClass('ui-state-default')) { // a date link
$('.ui-datepicker-close')[0].focus();
} else if ($(target).hasClass('ui-datepicker-prev')) { // the prev link
$('.ui-datepicker-next')[0].focus();
} else if ($(target).hasClass('ui-datepicker-next')) { // the next link
activeDate = $('.ui-state-highlight') ||
$('.ui-state-active')[0];
if (activeDate) {
activeDate.focus();
}
}
} else if (which === 9) { // TAB
keyVent.preventDefault();
if ($(target).hasClass('ui-datepicker-close')) { // close button
activeDate = $('.ui-state-highlight') ||
$('.ui-state-active')[0];
if (activeDate) {
activeDate.focus();
}
} else if ($(target).hasClass('ui-state-default')) {
$('.ui-datepicker-next')[0].focus();
} else if ($(target).hasClass('ui-datepicker-next')) {
$('.ui-datepicker-prev')[0].focus();
} else if ($(target).hasClass('ui-datepicker-prev')) {
$('.ui-datepicker-close')[0].focus();
}
} else if (which === 37) { // LEFT arrow key
// if we're on a date link...
if (!$(target).hasClass('ui-datepicker-close') && $(target).hasClass('ui-state-default')) {
keyVent.preventDefault();
previousDay(target);
}
} else if (which === 39) { // RIGHT arrow key
// if we're on a date link...
if (!$(target).hasClass('ui-datepicker-close') && $(target).hasClass('ui-state-default')) {
keyVent.preventDefault();
nextDay(target);
}
} else if (which === 38) { // UP arrow key
if (!$(target).hasClass('ui-datepicker-close') && $(target).hasClass('ui-state-default')) {
keyVent.preventDefault();
upHandler(target, container, prev);
}
} else if (which === 40) { // DOWN arrow key
if (!$(target).hasClass('ui-datepicker-close') && $(target).hasClass('ui-state-default')) {
keyVent.preventDefault();
downHandler(target, container, next);
}
} else if (which === 13) { // ENTER
if ($(target).hasClass('ui-state-default')) {
setTimeout(function() {
closeCalendar(element);
}, 100);
} else if ($(target).hasClass('ui-datepicker-prev')) {
handlePrevClicks();
} else if ($(target).hasClass('ui-datepicker-next')) {
handleNextClicks();
}
} else if (32 === which) {
if ($(target).hasClass('ui-datepicker-prev') || $(target).hasClass('ui-datepicker-next')) {
target.click();
}
} else if (33 === which) { // PAGE UP
keyVent.preventDefault();
moveOneMonth(target, 'prev');
} else if (34 === which) { // PAGE DOWN
keyVent.preventDefault();
moveOneMonth(target, 'next');
} else if (36 === which) { // HOME
var firstOfMonth = $(target).closest('tbody').find('.ui-state-default')[0];
if (firstOfMonth) {
firstOfMonth.focus();
setHighlightState(firstOfMonth, $('#ui-datepicker-div')[0]);
}
} else if (35 === which) { // END
var $daysOfMonth = $(target).closest('tbody').find('.ui-state-default');
var lastDay = $daysOfMonth[$daysOfMonth.length - 1];
if (lastDay) {
lastDay.focus();
setHighlightState(lastDay, $('#ui-datepicker-div')[0]);
}
}
$(".ui-datepicker-current").hide();
});
return false;
}

function closeCalendar(element) {

var container = $('#ui-datepicker-div');
$(container).off('keydown');
// var input = $('#datepicker')[0];
// $(input).datepicker('hide');
//
// input.focus();
//console.log(element[0].previousSibling);
$(element[0].previousSibling).datepicker('hide'); //this gives access to input field beside it

element[0].focus(); // Focus the button
}

function removeAria() {
// make the rest of the page accessible again:
$("#dp-container").removeAttr('aria-hidden');
$("#skipnav").removeAttr('aria-hidden');
}

///////////////////////////////
//////////////////////////// //
///////////////////////// // //
// UTILITY-LIKE THINGS // // //
///////////////////////// // //
//////////////////////////// //
///////////////////////////////
function isOdd(num) {
return num % 2;
}

function moveOneMonth(currentDate, dir) {
var button = (dir === 'next') ?
$('.ui-datepicker-next')[0] :
$('.ui-datepicker-prev')[0];

if (!button) {
return;
}

var ENABLED_SELECTOR = '#ui-datepicker-div tbody td:not(.ui-state-disabled)';
var $currentCells = $(ENABLED_SELECTOR);
var currentIdx = $.inArray(currentDate.parentNode, $currentCells);

button.click();
setTimeout(function() {
updateHeaderElements();

var $newCells = $(ENABLED_SELECTOR);
var newTd = $newCells[currentIdx];
var newAnchor = newTd && $(newTd).find('a')[0];

while (!newAnchor) {
currentIdx--;
newTd = $newCells[currentIdx];
newAnchor = newTd && $(newTd).find('a')[0];
//Updated by shiva incase user is trying to access page up/down at high speed newAnchor is undefnied in which case use day 1 as cursor.
if (newAnchor == undefined) {
newAnchor = $("td[data-handler='selectDay']")[0].children[0]
}
}

setHighlightState(newAnchor, $('#ui-datepicker-div')[0]);
newAnchor.focus();

}, 0);

}

function handleNextClicks() {
setTimeout(function() {
updateHeaderElements();
prepHighlightState();
$('.ui-datepicker-next').focus();
$(".ui-datepicker-current").hide();
}, 0);
}

function handlePrevClicks() {
setTimeout(function() {
updateHeaderElements();
prepHighlightState();
$('.ui-datepicker-prev').focus();
$(".ui-datepicker-current").hide();
}, 0);
}

function previousDay(dateLink) {
var container = document.getElementById('ui-datepicker-div');
if (!dateLink) {
return;
}
var td = $(dateLink).closest('td');
if (!td) {
return;
}

var prevTd = $(td).prev(),
prevDateLink = $('a.ui-state-default', prevTd)[0];

if (prevTd && prevDateLink) {
setHighlightState(prevDateLink, container);
prevDateLink.focus();
} else {
handlePrevious(dateLink);
}
}
function handlePrevious(target) {
var container = document.getElementById('ui-datepicker-div');
if (!target) {
return;
}
var currentRow = $(target).closest('tr');
if (!currentRow) {
return;
}
var previousRow = $(currentRow).prev();

if (!previousRow || previousRow.length === 0) {
// there is not previous row, so we go to previous month...
previousMonth();
} else {
var prevRowDates = $('td a.ui-state-default', previousRow);
var prevRowDate = prevRowDates[prevRowDates.length - 1];

if (prevRowDate) {
setTimeout(function() {
setHighlightState(prevRowDate, container);
prevRowDate.focus();
}, 0);
}
}
}

function previousMonth() {
var prevLink = $('.ui-datepicker-prev')[0];
var container = document.getElementById('ui-datepicker-div');
prevLink.click();
// focus last day of new month
setTimeout(function() {
var trs = $('tr', container),
lastRowTdLinks = $('td a.ui-state-default', trs[trs.length - 1]),
lastDate = lastRowTdLinks[lastRowTdLinks.length - 1];

// updating the cached header elements
updateHeaderElements();

setHighlightState(lastDate, container);
lastDate.focus();

}, 0);
}

///////////////// NEXT /////////////////
/**
* Handles right arrow key navigation
* @param {HTMLElement} dateLink The target of the keyboard event
*/
function nextDay(dateLink) {
var container = document.getElementById('ui-datepicker-div');
if (!dateLink) {
return;
}
var td = $(dateLink).closest('td');
if (!td) {
return;
}
var nextTd = $(td).next(),
nextDateLink = $('a.ui-state-default', nextTd)[0];

if (nextTd && nextDateLink) {
setHighlightState(nextDateLink, container);
nextDateLink.focus(); // the next day (same row)
} else {
handleNext(dateLink);
}
}

function handleNext(target) {
var container = document.getElementById('ui-datepicker-div');
if (!target) {
return;
}
var currentRow = $(target).closest('tr'),
nextRow = $(currentRow).next();

if (!nextRow || nextRow.length === 0) {
nextMonth();
} else {
var nextRowFirstDate = $('a.ui-state-default', nextRow)[0];
if (nextRowFirstDate) {
setHighlightState(nextRowFirstDate, container);
nextRowFirstDate.focus();
}
}
}

function nextMonth() {
nextMon = $('.ui-datepicker-next')[0];
var container = document.getElementById('ui-datepicker-div');
nextMon.click();
// focus the first day of the new month
setTimeout(function() {
// updating the cached header elements
updateHeaderElements();

var firstDate = $('a.ui-state-default', container)[0];
setHighlightState(firstDate, container);
firstDate.focus();
}, 0);
}

/////////// UP ///////////
/**
* Handle the up arrow navigation through dates
* @param {HTMLElement} target The target of the keyboard event (day)
* @param {HTMLElement} cont The calendar container
* @param {HTMLElement} prevLink Link to navigate to previous month
*/
function upHandler(target, cont, prevLink) {
prevLink = $('.ui-datepicker-prev')[0];
var rowContext = $(target).closest('tr');
if (!rowContext) {
return;
}
var rowTds = $('td', rowContext),
rowLinks = $('a.ui-state-default', rowContext),
targetIndex = $.inArray(target, rowLinks),
prevRow = $(rowContext).prev(),
prevRowTds = $('td', prevRow),
parallel = prevRowTds[targetIndex],
linkCheck = $('a.ui-state-default', parallel)[0];

if (prevRow && parallel && linkCheck) {
// there is a previous row, a td at the same index
// of the target AND theres a link in that td
setHighlightState(linkCheck, cont);
linkCheck.focus();
} else {
// we're either on the first row of a month, or we're on the
// second and there is not a date link directly above the target
prevLink.click();
setTimeout(function() {
// updating the cached header elements
updateHeaderElements();
var newRows = $('tr', cont),
lastRow = newRows[newRows.length - 1],
lastRowTds = $('td', lastRow),
tdParallelIndex = $.inArray(target.parentNode, rowTds),
newParallel = lastRowTds[tdParallelIndex],
newCheck = $('a.ui-state-default', newParallel)[0];

if (lastRow && newParallel && newCheck) {
setHighlightState(newCheck, cont);
newCheck.focus();
} else {
// theres no date link on the last week (row) of the new month
// meaning its an empty cell, so we'll try the 2nd to last week
var secondLastRow = newRows[newRows.length - 2],
secondTds = $('td', secondLastRow),
targetTd = secondTds[tdParallelIndex],
linkCheck = $('a.ui-state-default', targetTd)[0];

if (linkCheck) {
setHighlightState(linkCheck, cont);
linkCheck.focus();
}

}
}, 0);
}
}

//////////////// DOWN ////////////////
/**
* Handles down arrow navigation through dates in calendar
* @param {HTMLElement} target The target of the keyboard event (day)
* @param {HTMLElement} cont The calendar container
* @param {HTMLElement} nextLink Link to navigate to next month
*/
function downHandler(target, cont, nextLink) {
nextLink = $('.ui-datepicker-next')[0];
var targetRow = $(target).closest('tr');
if (!targetRow) {
return;
}
var targetCells = $('td', targetRow),
cellIndex = $.inArray(target.parentNode, targetCells), // the td (parent of target) index
nextRow = $(targetRow).next(),
nextRowCells = $('td', nextRow),
nextWeekTd = nextRowCells[cellIndex],
nextWeekCheck = $('a.ui-state-default', nextWeekTd)[0];

if (nextRow && nextWeekTd && nextWeekCheck) {
// theres a next row, a TD at the same index of `target`,
// and theres an anchor within that td
setHighlightState(nextWeekCheck, cont);
nextWeekCheck.focus();
} else {
nextLink.click();

setTimeout(function() {
// updating the cached header elements
updateHeaderElements();

var nextMonthTrs = $('tbody tr', cont),
firstTds = $('td', nextMonthTrs[0]),
firstParallel = firstTds[cellIndex],
firstCheck = $('a.ui-state-default', firstParallel)[0];

if (firstParallel && firstCheck) {
setHighlightState(firstCheck, cont);
firstCheck.focus();
} else {
// lets try the second row b/c we didnt find a
// date link in the first row at the target's index
var secondRow = nextMonthTrs[1],
secondTds = $('td', secondRow),
secondRowTd = secondTds[cellIndex],
secondCheck = $('a.ui-state-default', secondRowTd)[0];

if (secondRow && secondCheck) {
setHighlightState(secondCheck, cont);
secondCheck.focus();
}
}
}, 0);
}
}
function onCalendarHide() {
closeCalendar();
}

// add an aria-label to the date link indicating the currently focused date
// (formatted identically to the required format: mm/dd/yyyy)
function monthDayYearText() {
var cleanUps = $('.amaze-date');

$(cleanUps).each(function(clean) {
// each(cleanUps, function (clean) {
clean.parentNode.removeChild(clean);
});

var datePickDiv = document.getElementById('ui-datepicker-div');
// in case we find no datepick div
if (!datePickDiv) {
return;
}

var dates = $('a.ui-state-default', datePickDiv);

$(dates).each(function(index, date) {
var currentRow = $(date).closest('tr'),
currentTds = $('td', currentRow),
currentIndex = $.inArray(date.parentNode, currentTds),
headThs = $('thead tr th', datePickDiv),
dayIndex = headThs[currentIndex],
daySpan = $('span', dayIndex)[0],
monthName = $('.ui-datepicker-month', datePickDiv)[0].innerHTML,
year = $('.ui-datepicker-year', datePickDiv)[0].innerHTML,
number = date.innerHTML;

if (!daySpan || !monthName || !number || !year) {
return;
}

// AT Reads: {month} {date} {year} {day}
// "December 18 2014 Thursday"
var dateText = monthName + ' ' + date.innerHTML + ' ' + year + ' ' + daySpan.title;
// AT Reads: {date(number)} {name of day} {name of month} {year(number)}
// var dateText = date.innerHTML + ' ' + daySpan.title + ' ' + monthName + ' ' + year;
// add an aria-label to the date link reading out the currently focused date
date.setAttribute('aria-label', dateText);
});
}

// update the cached header elements because we're in a new month or year
function updateHeaderElements() {
var context = document.getElementById('ui-datepicker-div');
if (!context) {
return;
}

$(context).find('table').first().attr('role', 'grid');

prev = $('.ui-datepicker-prev', context)[0];
next = $('.ui-datepicker-next', context)[0];

//make them click/focus - able
next.href = 'javascript:void(0)';
prev.href = 'javascript:void(0)';

next.setAttribute('role', 'button');
prev.setAttribute('role', 'button');
appendOffscreenMonthText(next);
appendOffscreenMonthText(prev);

$(next).on('click', handleNextClicks);
$(prev).on('click', handlePrevClicks);

// add month day year text
monthDayYearText();
}
function prepHighlightState() {
var highlight;
var cage = document.getElementById('ui-datepicker-div');
highlight = $('.ui-state-highlight', cage)[0] ||
$('.ui-state-default', cage)[0];
if (highlight && cage) {
setHighlightState(highlight, cage);
}
}

// Set the highlighted class to date elements, when focus is recieved
function setHighlightState(newHighlight, container) {
var prevHighlight = getCurrentDate(container);
// remove the highlight state from previously
// highlighted date and add it to our newly active date
$(prevHighlight).removeClass('ui-state-highlight');
$(newHighlight).addClass('ui-state-highlight');
}
// grabs the current date based on the hightlight class
function getCurrentDate(container) {
var currentDate = $('.ui-state-highlight', container)[0];
return currentDate;
}

/**
* Appends logical next/prev month text to the buttons
* - ex: Next Month, January 2015
* Previous Month, November 2014
*/
function appendOffscreenMonthText(button) {
var buttonText;
var isNext = $(button).hasClass('ui-datepicker-next');
var months = [
'january', 'february',
'march', 'april',
'may', 'june', 'july',
'august', 'september',
'october',
'november', 'december'
];

var currentMonth = $('.ui-datepicker-title .ui-datepicker-month').text().toLowerCase();
var monthIndex = $.inArray(currentMonth.toLowerCase(), months);
var currentYear = $('.ui-datepicker-title .ui-datepicker-year').text().toLowerCase();
var adjacentIndex = (isNext) ? monthIndex + 1 : monthIndex - 1;

if (isNext && currentMonth === 'december') {
currentYear = parseInt(currentYear, 10) + 1;
adjacentIndex = 0;
} else if (!isNext && currentMonth === 'january') {
currentYear = parseInt(currentYear, 10) - 1;
adjacentIndex = months.length - 1;
}

buttonText = (isNext) ?
'Next Month, ' + firstToCap(months[adjacentIndex]) + ' ' + currentYear :
'Previous Month, ' + firstToCap(months[adjacentIndex]) + ' ' + currentYear;

$(button).find('.ui-icon').html(buttonText);

}

// Returns the string with the first letter capitalized
function firstToCap(s) {
return s.charAt(0).toUpperCase() + s.slice(1);
}

 

Websphere Portal theme – uncompressed css/js

If you are seeing uncompressed css/js files loading in your theme instead of compressed it could be because of following trace enabled on the server.

com.ibm.wps.resourceaggregator.CombinerDataSource.RemoteDebug=all

When debug is enabled, the modules that contribute to the theme provide their uncompressed Javascript or CSS files if available. Additionally, all the files are retrieved with separate requests. This makes it much easier to find the offending file.

uncompressed

jQuery – Modify Primefaces Radiobutton

Updating Primefaces radiobutton using javascript is tricky.

Below code can be used to enable or clear a particular radio button.

enableRadioButton($(“[id*=’RADIOFIELDNAME:0′]”));
clearRadioButton($(“[id*=’RADIOFIELDNAME:1′]”));

function enableRadioButton(obj)
{

var a = obj.parent();
obj.prop(“checked”, true);
a.parent().children(‘.ui-radiobutton-box’).addClass(
“ui-state-active”).children(“.ui-radiobutton-icon”)
.addClass(“ui-icon-bullet”).removeClass(
“ui-icon-blank”);
}
function clearRadioButton(obj)
{
var a = obj.parent();
obj.prop(“checked”, false);
a.parent().children(‘.ui-radiobutton-box’).removeClass(
“ui-state-active”).children(“.ui-radiobutton-icon”)
.removeClass(“ui-icon-bullet”).addClass(
“ui-icon-blank”);

}

Customize Portal Session Timeout Message

Sometimes client would like to customise the default message displayed when WebSphere portal session time’s out.

It can be done by following below steps

  1. Extract the file engine.properties to the portal_server_root/shared/app/nls directory.
  2. Edit engine.properties and change the “error.timeout” parameter to the message that you want to be displayed when session expires.
  3. Save and close engine.properties.
  4. Restart portal server.

For multilingual sites, the file can have a language suffix corresponding to the locale, for example, engine_es.properties for Spanish.

error.timeout = You are too much time away from desk .. your session expired {0}.
error.timeout.answer = If a session is inactive too long, it is terminated for security reasons. Please log in again.

I think there are other ways to do as well which I did not test , like modifying properties  wp.ui.jar in C:\Program Files (x86)\IBM\WebSphere\PortalServer\ui\wp.ui\shared\app

 

XSS – Sanatize Input

XSS is the most prevalent web application security flaw. XSS flaws occur when an application includes user supplied data in a page sent to the browser without properly validating or escaping that content.

There are many libraries online which can be used to prevent XSS but after trying most of the libraries I see AntiSamy library solves most of the scenarios.

The OWASP AntiSamy project is a few things. Technically, it is an API for ensuring user-supplied HTML/CSS is in compliance within an application’s rules. Another way of saying that could be: It’s an API that helps you make sure that clients don’t supply malicious cargo code in the HTML they supply for their profile, comments, etc., that get persisted on the server. The term “malicious code” in regards to web applications usually mean “JavaScript.” Cascading Stylesheets are only considered malicious when they invoke the JavaScript engine.

Customized Anti Sammy XML can be found here

antisamy-customized-1-4-3


import org.owasp.validator.html.*;

import java.util.regex.Pattern;
public class WebSecurityAPI {

private static final String POLICY_FILE_LOCATION = "com/application/security/policy/antisamy-customized-1.4.3.xml";
/*
* returns sanitized HTML*/
public static synchronized String sanitizeHTML(String input) throws PolicyException, ScanException {
ClassLoader CLDR = WebSecurityAPI.class.getClassLoader();
Policy policy = Policy.getInstance(CLDR.getResourceAsStream (POLICY_FILE_LOCATION));
AntiSamy as = new AntiSamy();
CleanResults cr = as.scan(input, policy, AntiSamy.SAX);
return cr.getCleanHTML();
}
}

 


import com.application.security.util.WebSecurityAPI;

/**
* @author Shiva Arvapalli
*
*/
public class SanatizeTest {

public static void main(String[] args)
{
try {
String dirtyInput = "\" Pour ac'c�der au journal de test<script>alert(1)</script>onMouseOver=\"alert(1);In anticipation of your t\"entative\" June 2016 Call to the Bar of Ontario, we ask that you select a call location by <strong>April</strong> 4 of this year.sd"; // Some fake input
String clearHTML=WebSecurityAPI.sanitizeHTML(dirtyInput);
System.out.println(clearHTML); // Do something with your clean output!
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

 

Accessibility Testing – Useful links

WAVE – Web Accessiblity Evaluation Tool

http://wave.webaim.org/extension/

The WAVE Chrome extension allows you to evaluate web content for accessibility issues directly within Chrome. Because the extension runs entirely within your web browser, no information is sent to the WAVE server.unnamed

 

NVAccess – Free screen reader software for testing accessibility of the website

Homepage

NVDA (NonVisual Desktop Access) is a free “screen reader” which enables blind and vision impaired people to use computers. It reads the text on the screen in a computerised voice. You can control what is read to you by moving the cursor to the relevant area of text with a mouse or the arrows on your keyboard.

 

  • Use NVDA to test software or website accessibility.
  • Ensure text, links, graphics etc. can be “read” by a blind person.
  • NVDA is free.
  • Easy to download.
  • Speech viewer (text) available as well as screen reader voice.

JSF redirect on page load

In JSF 2.0, you can use javax.faces.event.PreRenderViewEvent system event to perform custom logic before JSF page is displayed.

For eg : If user belongs to admin group you would like to redirect the user to Administration page and if its a normal user should be redirected to a different page.

<?xml version=”1.0″ encoding=”UTF-8″?>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”&gt;
<html xmlns=”http://www.w3.org/1999/xhtml&#8221;
xmlns:h=”http://java.sun.com/jsf/html&#8221;
xmlns:f=”http://java.sun.com/jsf/core&#8221;
>

<f:event listener=”#{pageBean.isUserAdministrator}” type=”preRenderView” />

<h:body>

<h:outputText value=”Default Page ..” />

</h:body>

</html>


 

public void isUserAdministrator(ComponentSystemEvent event){
//If logged with admin ID
 if(userBean.getWpsadmin()!=null &amp;amp;amp;amp;&amp;amp;amp;amp; userBean.getWpsadmin().compareTo(Constants.WPSADMIN)==0)
 {
 //Redirect to admin page
 userBean.gotoPage(Constants.ADMINXHTML);
 }
else
{
//Redirect to normal page
}
 }
//Redirection ...
public void gotoPage(String pageName) {
 if (pageName != null) {
 FacesContext context = getFacesContext();
 UIViewRoot newView =
 context.getApplication().getViewHandler().createView(
 context,
 pageName);
 context.setViewRoot(newView);
 context.renderResponse();
 }
 }

WebSphere Portal Security Considerations

Setting headers on IBM HTTP Server

Stop the HTTP server.
Log on to the web server and edit the following file:
/opt/IBM/HTTPServer/conf/httpd.conf
Enable below module –

LoadModule headers_module modules/mod_headers.so

<ifModule mod_headers.c>
Header set X-Permitted-Cross-Domain-Policies “none”
Header set X-XSS-Protection “1; mode=block”
Header set X-Frame-Options “DENY”
</ifModule>

Restart the HTTP server.

Setting headers on WebSphere Application server – optional

WebSphere Portal offers protection against XSS, enabled with the security.css.protection setting in the Configuration Service.

Above setting should be enabled by default

WebSphere Application Server offers protection against XSS, enabled with the com.ibm.ws.security.addHttpOnlyAttributeToCookies custom property for Global Security. When set, the HTTP-only attribute, HttpOnly, will be set for LTPA tokens. Browsers will not allow scripts access to cookies for which HTTPOnly is set

X-Frame-Options Response Header

Log into WebSphere Integrated Solutions Console as the WebSphere Administrator user.
In the left panel, open Servers, and then open Server Types. Click WebSphere application servers.
In the Application servers table, click the server where InfoSphere Business Glossary is installed.
Under Server Infrastructure, open Java and Process Management, and then click Process definition.
Under Additional Properties, click Java Virtual Machine.
Under Additional Properties, click Custom Properties.
Click New. Complete these steps to create and apply a system configuration property:
In the Name field, type bg.xFrameOptions.
In the Value field, type in the X-Frame-Option HTTP response header that you need (for example: SAMEORIGIN).
Click Apply, and then click OK.
In the Messages window, click Save to save the new property when WebSphere Application Server is restarted.
Stop and restart WebSphere Application Server.

JBoss Fuse ESB Local Env Setup

Useful Instructions for setting up JBoss Fuse ESB on EAP:

https://developers.redhat.com/products/fuse/get-started/#tab-eapRuntime

Please install Java8 and Apache Maven.

==========================Java 8======================

Download JDK 8 – 1.8.0_20 : http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

=================Apache Maven : Download link=================================

https://maven.apache.org/download.cgi?Preferred=ftp://mirror.reverse.net/pub/apache/

Windows Instructions:
Check environment variable value e.g.

C:\Windows\system32>echo %JAVA_HOME%
C:\Program Files\Java\jdk1.8.0_20
Adding to PATH: Add the unpacked distribution’s bin directory to your user PATH environment variable by opening up the system properties (WinKey + Pause), selecting the “Advanced” tab, and the “Environment Variables” button, then adding or selecting the PATH variable in the user variables with the value C:\Program Files\apache-maven-3.3.9\bin.

The same dialog can be used to set JAVA_HOME to the location of your JDK, e.g. C:\Program Files\Java\jdk1.8.0_20

Open a new command prompt (Winkey + R then type cmd) and run mvn -v to verify the installation.
==============End of Apache Maven=============================================

Also signup for redhat developer website as it might be required later.

https://developers.redhat.com/auth/realms/rhd/protocol/openid-connect/registrations?client_id=web&redirect_uri=https%3A%2F%2Fdevelopers.redhat.com%2F%2Fconfirmation&state=cd08b2de-4ca5-4802-a670-c6bb22da3c83&nonce=566e644b-0598-4192-8b2e-fdc90c25475e&response_mode=fragment&response_type=code

Sometimes connecting to maven is tricky , below sample settings file can be used as a reference.


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository/>
<profiles>
<profile>
<id>jboss-ga</id>
<repositories>
<repository>
<id>jboss-ga-repository</id>
<name>JBoss GA Tech Preview Maven Repository</name>
<url>http://maven.repository.redhat.com/techpreview/all</url>
<layout>default</layout>
<releases>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
<updatePolicy>never</updatePolicy>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>jboss-ga-plugin-repository</id>
<name>JBoss 6 Maven Plugin Repository</name>
<url>http://maven.repository.redhat.com/techpreview/all</url>
<layout>default</layout>
<releases>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
<updatePolicy>never</updatePolicy>
</snapshots>
</pluginRepository>
</pluginRepositories>

</profile>
<profile>
<id>jboss-earlyaccess-repository</id>
<repositories>
<repository>
<id>jboss-earlyaccess-repository</id>
<name>jboss-earlyaccess-repository</name>
<url>http://maven.repository.redhat.com/earlyaccess/all/</url>
<releases>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>jboss-earlyaccess-repository</id>
<name>jboss-earlyaccess-repository</name>
<url>http://maven.repository.redhat.com/earlyaccess/all/</url>
<releases>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>jboss-ga</activeProfile>
</activeProfiles>
<proxies>
<proxy>
<active>true</active>
<protocol>http</protocol>
<host>proxyhostname</host>
<port>8082</port>
<username/>
<password/>
<nonProxyHosts>localhost,127.0.0.1</nonProxyHosts>
</proxy>
</proxies>

</settings>

 

Primefaces input number retun 0 for empty value

Ever experienced p:inputNumber tag with empty value submitted and bean storing them as 0’s instead of null or empty ? Its because of org.apache.el.parser.COERCE_TO_ZERO , see below how we can resolve this issue.

I’m using InputNumber with emptyValue=”empty”. But empty input fields always display zero instead of blank or empty value

<p:inputNumber size=”5″ emptyValue=”empty” id=”MSSONB” value=”#{pageBean.mar.MSSONB}” widgetVar=”MSSONBVar” />

Primefaces : 6.0.8
JSF 2.0
WebSphere Portal 8

Example in primefaces showcase seems to work – http://www.primefaces.org/showcase/ui/i … mber.xhtml
but when we try to test the same code as in showcase it does not work.

org.apache.el.parser.COERCE_TO_ZERO

Allows for the expression language (EL) that WebSphere Application Server uses to coerce null and empty string integer values to a 0 value or for NOT allowing a coerce to a 0 value and retaining the null or empty string integer. The default is true and permits a null or empty string integer value to be coerced to a 0 value.
Important: To keep a null value from being coerced to a 0 value in a MyFaces application, the following context parameter in the web.xml of the application: should be set to ensure that all possible instances of an empty or null value are inhibited from being coerced to zero.
<context-param>
<param-name>javax.faces.
INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL
</param-name>
<param-value>true</param-value>
</context-param>
You set the org.apache.el.parser.COERCE_TO_ZERO property using the administrative console.
Expand Servers, and then select WebSphere Application Servers. Click on the appropriate server from the list.
Under Server Infrastructure, expand Java and Process Management > Click on Process definition.
Under Additional Properties, click Java virtual machine.
Under Additional Properties, click Custom properties.
Click New and add the org.apache.el.parser.COERCE_TO_ZERO property with the value of false if you do NOT want a null value coerced to zero.
Click Save to save the change and restart the WebSphere Application Server to ensure that the change takes place.